【问题标题】:Compiled vs Interpreted: To Let or Not To Let编译与解释:让或不让
【发布时间】:2017-02-26 16:19:33
【问题描述】:

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

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

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

【问题讨论】:

  • 这是一个约定。如果 GHCi 的工作方式与写入 .hs 文件完全相同,那么写入 1+1print (2,3) 将是一个错误。相反,GCHi 选择使用一点魔法来接受这些表达式和let 定义。关于为什么不带 let 的 x=1 会被拒绝——我认为除了“它需要更多魔法”之外,没有明确的答案。
  • 对。 FWIW,IHaskell 允许混合两种样式。
  • 最新版本的 GHCi (8.0.1) 接受doubleMe x = x + x。像你这样的人抱怨他们为此添加了一个特殊情况。 :)
  • 这是我现在欣赏 Haskell 和 Lisp 之间的根本区别:分别通过命令提示符对编译器进行交互式访问与通过 REPL 对语言本身进行交互式访问。

标签: haskell compilation ghci interpretation


【解决方案1】:

现代 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 本身交互。

【讨论】:

    【解决方案2】:

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

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

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

    同样你可以写

    let f x = 2 * x
    

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

    【讨论】:

      【解决方案3】:

      这背后的原因是 GHCi(在 7.10.3 中)只需要提示符

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

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

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

      【讨论】:

      • 这与编译和解释无关。我相信很多 Lisp 实际上是编译的,尽管我认为 Scheme 可能是唯一真正为良好编译而设计的 Lisp。
      • 我怀疑在早期版本的 ghci 中不包含此功能的真正动机是令人惊讶的行为,例如ghci 中的maybeDoubleMe Nothing = Nothing\nmaybeDoubleMe (Just x) = Just (x+x) 与文件中的比较。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多