Search code examples
bashhaskellghcirunhaskell

Why does ghci behave differently to runHaskell?


My goal is to pipe some steps for ghci to run from a bash script and then exit cleanly. The commentary online says to use runhaskell for this.

This is the command I'm trying to run:

ghci> import System.Random 

ghci> random (mkStdGen 100) :: (Int, StdGen) 

With expected result similar to:

(-3633736515773289454,693699796 2103410263)

When I drop this into a file randomtest.hs and execute it with runhaskell I get the following error:.

randomtest.hs:3:1: error:
    Invalid type signature: random (mkStdGen 100) :: ...
    Should be of form <variable> :: <type>

I need a hint to go in the right direction.

My question is: Why does ghci behave differently to runHaskell?


Solution

  • ghci is a REPL (Read, Eval, Print Loop). However, runhaskell is nearly the same as compiling a program into an executable, and then running it. GHCI lets us run individual functions and arbitrary expressions, wheras runhaskell just calls the main function and interprets the file, instead of compiling it, and running that.

    As @AJFarmar points out, GHCI is best used to debug and test a program you're building, whilst runhaskell is a nice way to run a whole program without having to compile.

    So, to fix your issue, we just need to give the program a main function. ghci calls print on the result of every expression which is typed into the interpreter and not bound to a variable.

    So, our main function can just be:

    main = print (random (mkStdGen 100) :: (Int, StdGen))

    We still need to import System.Random, so the whole file becomes:

    import System.Random
    
    main = print (random (mkStdGen 100) :: (Int, StdGen))
    

    Then, we can run as expected:

    [~]λ runhaskell randomtest.hs 
    (-3633736515773289454,693699796 2103410263)
    

    If we want to multiple commands from runhaskell we can just add more to a do block in main:

    import System.Random
    
    main = do
        print (random (mkStdGen 100) :: (Int, StdGen))
        let x = 5 * 5
        print x
        putStrLn "Hello world!"