4

它...有点工作你们(这绝对编译,改编自https://hackage.haskell.org/package/scotty):

main :: IO ()
main = (do
  (putStrLn "Starting Server....")
  (scotty 3000 (do
    (get "/hello/:name"
        (text ("hello " <> (param "name") <> "!")))

    (get "/users"
      (json allUsers))

    (get "/users/:id"
      (json (filter (matchesId (param "id")) allUsers))))))

(我不知道足够的haskell 转换<>为简单的parens,但聪明的人可以很容易地。)

我们为什么要这样做?我们可以使用任何 lisp 宏引擎对 Haskell 进行预处理!琐碎!。

想象一下。HASKELL 和 LISP 在一起。我们可以统治银河!

在此处输入图像描述

(我知道你的想法,但我实际上已经考虑过了:在这个例子中,Vader 是 Lisp,Luke 是 Haskell,Yoda 是 Alonzo Church)

(编辑“感谢所有回答和评论的人,我现在更聪明了。我认为尚未提到的这种技术的最大问题,并被朋友 IRL 指出:如果你编写一些 lispy 预处理器,你在你的 IDE 和工具中失去类型检查和语法突出显示和理解。这听起来像是我的硬通行证。

“我现在正在关注https://github.com/finkel-lang/finkel项目,这是我想要的 lisp 风格的 haskell 项目!” )

4

3 回答 3

7

Haskell 的语法在历史上是从 ISWIM 派生的,ISWIM是一种出现在 LISP 之后不久的语言,在 Peter J. Landin 1966 年的文章The Next 700 Programming Languages中进行了描述。

第 6 节专门讨论与 LISP 的关系:

ISWIM 可以被看作是试图将 LISP 从其对列表的同名承诺、手到嘴存储分配的声誉、其教学法的硬件依赖风格、 繁重的括号以及与传统的妥协中解脱出来。

稍后在同一部分:

ISWIM 的文本外观不像 LISP 的 S 表达式。它更接近 LISP 的 M 表达式(构成一种非正式语言,用作手动准备 LISP 程序的中间结果)。ISWIM 具有以下附加功能: [...]

因此,有明确的意图与 LISP 语法或至少与 S 表达式不同。

于 2020-02-29T14:00:52.160 回答
6

在结构上,Haskell 程序由一组模块组成。每个模块由一组声明组成。模块和声明是惰性的——仅靠它们的存在不会导致任何事情发生。它们只是在静态命名空间中形成条目,编译器在生成代码时使用这些条目来解析名称。

顺便说一句,你可能会在Main.main这里狡辩。作为入口点,它只是为了被定义而运行。这还算公平。但是所有其他声明仅在需要时才用于代码生成Main.main,而不仅仅是因为它存在。

相比之下,Lisp 是更动态的系统。Lisp 程序由一系列按顺序执行的 s 表达式组成。每一个都会导致代码执行具有任意副作用,包括修改全局命名空间。

在这里,事情变得更加基于意见。我认为 Lisp 的动态结构与其语法的规律性密切相关。语法检查无法区分旨在将值添加到全局名称空间的 s 表达式和旨在运行其副作用的表达式。如果没有句法区分,添加语义区分似乎很尴尬。因此,我认为 Lisp 语法在某种意义上过于规则,无法用于 Haskell 中不同类型代码之间具有严格语义分离的语言。相比之下,Haskell 的语法提供了句法区别来匹配语义区别。

于 2020-02-29T17:11:09.213 回答
3
  1. Haskell 没有 s-exp,因此括号仅用于标记归约和构造元组的优先级,这也意味着在 Haskell 中使用类似 lisp 的宏并不容易,因为它们大量使用 s-exp 和动态类型
  2. Haskell 有一个右关联函数应用程序(即 ($)),它涵盖了括号的大多数用例
  3. 空格在 Haskell 中具有语义意义,这就是我们大多数人写作的原因
do
  p1
  p2
  p3

代替

do { p1
   ; p2
   ; p3
   }
于 2020-02-29T15:29:52.697 回答