fpt
fpt

Reputation: 378

Compiled vs Interpreted: To Let or Not To Let

Why does the Haskell interpreter (GHCI 7.10.3) need function definitions to be in a let expression, but the Haskell compiler (GHC 7.10.3) throws a parser error if a function definition is within a let expression?

I'm working through "Learn You a Haskell for Great Good!" Baby's first function is doubleMe: doubleMe x = x + x

Why does the interpreter accept this definition if it is within a let expression and otherwise throw a parse error on input '='? Meanwhile, if I'm compiling the same function from a file, why does GHC throw a parse error if the function definition is within a let expression and compiles the definition if it is not within a let expression? Coming from a Lisp background, I'm surprised that interactive Haskell and file loading and compilation Haskell treats these definitions differently.

Upvotes: 1

Views: 610

Answers (3)

fpt
fpt

Reputation: 378

Modern Lisp implementations compile to native code, often by default even when code is entered at the prompt. Lisp's prompt isn't just a place to enter commands, it's a place to interact with the language because the entire language is made available by the Read-Evaluate-Print Loop. This means that Lisp reads the text into symbolic expressions, which it then evaluates, printing any print output and any returned values. For example,

? (defun a-fun () nil)
A-FUN
? (compiled-function-p #'a-fun)
T

Compiled-Function-P Clozure Common Lisp

With Lisp, code you can enter into the Lisp image by compiling and loading a file you can also enter into the Lisp image by typing it out at the REPL. So it turns out I was surprised because I was expecting the GHCi prompt to be a REPL, but as @Alec describes it's not because it doesn't read text into Haskell expressions that it would then evaluate, as Lisp does. As @dfeuer says, the issue isn't about compilation versus interpretation. The issue is that GHCi's prompt offers limited interaction with a Haskell compiler, rather than interaction with Haskell itself as Lisp's REPL does.

Upvotes: 0

Paul Johnson
Paul Johnson

Reputation: 17796

The GHCi interpreter command line treats its input as if it were in a do clause. So you can type this:

:module + System.Random
v <- getStdRandom $ randomR (1,10)

Apart from the :module directive this is exactly how it would be in a do clause.

Likewise you can write

let f x = 2 * x

because that is how it would be in a do clause.

Upvotes: 3

Alec
Alec

Reputation: 32319

The reasoning behind this is that GHCi (in 7.10.3) expects at the prompt only

  • commands (type in :h to list the commands available)
  • declarations (things like data, type, newtype, class, instance, deriving, and foreign but not a regular definition)
  • imports
  • expressions (things like 1+1 or let x = 3 in x*x)
  • I/O Actions / do statments (things like print "hi" or x <- getLine OR let doubleMe x = x + x)

If this seems surprising to you, remember that the evaluation of Lisp and Haskell is very different - Lisp just gets interpretted, while Haskell is being compiled.

As you can tell, top-level definitions are not part of this list. Thankfully this got fixed in GHCi 8.0.1, which now supports raw top-level function declarations. The following works (in 8.0.1):

ghci> doubleMe x = x + x
ghci> doubleMe 1
2

Upvotes: 4

Related Questions