为什么选择函数应用程序作为默认的Haskell运算符,而不是组合?

时间:2014-01-27 22:32:00

标签: haskell

与面向堆栈的语言中的f . g $ 3相比,Haskell语法需要相对嘈杂的3 g f。这个选择的主要设计论点是什么?

4 个答案:

答案 0 :(得分:12)

也可以写成f (g 3)

为什么Haskell不是一种连接语言?

基于A History of Haskell,它受到各种功能编程和懒惰语言实验的影响,包括ML。如第4节所述,语法描述:

  

柯里

     

遵循回归弗雷格的传统,两个参数的函数可以表示为一个参数的函数,该参数本身返回一个参数的函数。摩西施fonfinkel和Haskell Curry磨练了这一传统,后来被称为currying。函数应用程序由并置表示并与左侧相关联。因此,f x y被解析(f x) y。这导致简洁而强大的代码。例如,为了对列表中的每个数字求平方,我们写map square [1,2,3],而为了对列表列表中的每个数字求平方,我们写map (map square) [[1,2],[3]]。像许多其他基于lambda演算的语言一样,Haskell支持curried和uncurried定义,

currying的概念对Haskell的语义和lambda演算的核心至关重要,任何其他排列方法都会与语言交互不良。

答案 1 :(得分:11)

  1. 面向堆栈的样式并不像序列那样撰写;在Haskell中,3 g f是一种语言而不是f $ g $ 3。当然,这相当于f . g $ 3,但只有在您立即将合成应用于某个值时,它才有效。在Haskell中,您经常编写函数只是为了将它们交给某些更高阶的组合子,或者进行无点定义。在需要某种显式块的面向堆栈的语言中,在Haskell中它只需要.运算符。
  2. 通常,您不只是链接“原子”函数。当然,你不处理全球命名的单字母函数,所以微小的.$并没有真正产生明显的冗长差异。通常,正如嗯说的那样,你链接部分应用的函数,例如

    main = interact $ unlines . take 10 . filter ((>20) . length) . lines
    

    如果没有廉价的紧密绑定应用程序,那就更麻烦了。另外,分离.以标记未立即应用但仅仅是合成的内容是非常自然的。

答案 2 :(得分:2)

如果您对Haskell,Hudak,Hughes,Peyton Jones等人的历史感兴趣。 Wadler的"A History of Haskell: Being Lazy with Class"是关于这个主题的最着名的论文,值得一读。

它没有直接解决你的问题,但它确实指出了一个非常相关的事实:Haskell是作为小团队中一堆现有语言之间的统一折衷而创建的。引用第2.2节(“巴别塔”):

  

由于所有这些活动,到20世纪80年代中期,包括作者在内的许多研究人员对纯懒惰语言的设计和实现技术都非常感兴趣。事实上,我们中的许多人已经独立设计了我们自己的懒惰语言,并忙于为他们构建我们自己的实现。我们每个人都在写关于我们努力的论文,在我们描述我们的实现技术之前,我们首先要描述我们的语言。导致这个懒惰的巴别塔的语言包括:

     
      
  • Miranda [...]
  •   
  • Lazy ML(LML)[...]
  •   
  • 奥威尔[...]
  •   
  • Alfl [...]
  •   
  • Id [...]
  •   
  • 清洁[...]
  •   
  • 思考[...]
  •   
  • Daisy [...]
  •   

所以答案可能只是Haskell从其前身语言中复制了它。而且由于一堆这些语言反过来是基于Lisp和ML的灵感,所以他们可能类似地将它们从它们中复制出来。回过头来引用你的问题:

  

这个选择的主要设计理由是什么?

有可能从来没有持续的争论选择。在任何情况下,基于堆栈的设计都很少有高级语言,很少有人知道它们。

答案 3 :(得分:1)

我的猜测是lambda演算和实用性(在现实场景中)。

在lambda演算中,空间是应用,因此感觉与知道它的人更相似。

在大多数常用语言中,通常使用函数的方法是应用它。 Haskell不是基于堆栈的语言,所以选择是在那里做的。