1

为什么 Haskell 解释器 (GHCI 7.10.3) 需要函数定义在 let 表达式中,但如果函数定义在 let 表达式中,Haskell 编译器 (GHC 7.10.3) 会抛出解析器错误?

我正在完成“ Learn You a Haskell for Great Good!” Baby的第一个函数是doubleMe:doubleMe x = x + x

为什么解释器接受这个定义,如果它在一个 let 表达式中,否则在输入 '=' 上抛出一个解析错误?同时,如果我从文件中编译相同的函数,如果函数定义在 let 表达式中,为什么 GHC 会抛出解析错误,而如果它不在 let 表达式中,则编译定义?来自 Lisp 背景,我很惊讶交互式 Haskell 和文件加载和编译 Haskell 以不同的方式处理这些定义。

4

3 回答 3

4

这背后的原因是 GHCi(在 7.10.3 中)只期望在提示符下

  • 命令(键入:h以列出可用的命令)
  • 声明(例如data, type, newtype, class, instance, deriving,foreign不是常规定义)
  • 进口
  • 表达式(诸如1+1or之类的东西let x = 3 in x*x
  • I/O 动作/do语句(诸如print "hi"x <- getLine OR let doubleMe x = x + x之类的东西)

如果这让您感到惊讶,请记住 Lisp 和 Haskell 的评估非常不同 - Lisp 只是被解释,而 Haskell 正在编译。

如您所知,顶级定义不在此列表中。幸运的是,这在 GHCi 8.0.1 中得到了修复,它现在支持原始顶级函数声明。以下作品(在 8.0.1 中):

ghci> doubleMe x = x + x
ghci> doubleMe 1
2
于 2016-10-17T16:26:50.370 回答
3

GHCi 解释器命令行将其输入视为在do子句中。所以你可以输入这个:

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

除了:module指令之外,这正是它在do子句中的样子。

同样你可以写

let f x = 2 * x

因为这就是它在do子句中的样子。

于 2016-10-17T17:32:31.950 回答
0

现代 Lisp 实现编译为本机代码,通常默认情况下即使在提示符下输入代码也是如此。Lisp 的提示不仅仅是一个输入命令的地方,它还是一个与语言交互的地方,因为整个语言都可以通过 Read-Evaluate-Print Loop 获得。这意味着 Lisp 将文本读入符号表达式,然后对其进行评估,打印任何打印输出和任何返回值。例如,

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

Compiled-Function-P Clozure Common Lisp

使用 Lisp,您可以通过编译和加载文件将代码输入到 Lisp 图像中,您也可以通过在 REPL 中键入它来输入到 Lisp 图像中。所以事实证明我很惊讶,因为我期待 GHCi 提示符是一个 REPL,但正如@Alec所描述的那样,这并不是因为它不会像 Lisp 那样将文本读入 Haskell 表达式然后进行评估。正如@dfeuer所说,问题不在于编译与解释。问题是 GHCi 的提示提供了与 Haskell 编译器的有限交互,而不是像 Lisp 的 REPL 那样与 Haskell 本身交互。

于 2016-10-17T19:05:22.783 回答