当前位置:  开发笔记 > 编程语言 > 正文

Haskell,Lisp和冗长

如何解决《Haskell,Lisp和冗长》经验,为你挑选了7个好方法。

对于那些在Haskell和一些Lisp中都有经验的人,我很好奇是如何"愉快"(使用一个可怕的术语)是在Haskell和Lisp中编写代码.

一些背景:我学习Haskell现在,稍早有计划和CL(和一点点进军Clojure的)工作.传统上,你可以认为我是动态语言的粉丝,因为它们提供了简洁和快速.我很快就爱上了Lisp宏,因为它给了我另一种避免冗长和样板的方法.

我发现哈斯克尔难以置信的有趣,因为它把我介绍给编码我不知道的方式.它肯定有一些方面似乎有助于实现敏捷性,比如易于编写部分功能.不过,我有点担心失去Lisp的宏(我假设我失去他们,说实话我可能只是没有了解他们吗?)和静态类型系统.

会有人谁做了两个世界编码,像样的数目介意评论经验如何不同,您喜欢哪一种,如果说偏好的态势?



1> ShreevatsaR..:

简短回答:

你可以用高阶函数做几乎所有你可以做的事情(我包括monad,箭头等),但它可能需要更多的思考(但只是第一次,它很有趣,你会成为一个更好的程序员),和

静态系统足够通用,它永远不会妨碍你,有点令人惊讶的是它实际上"有助于实现敏捷性"(如你所说),因为当你的程序编译时你几乎可以肯定是正确的,所以这个确定性让你试试你可能会害怕尝试的东西 - 编程有"动态"的感觉,虽然它与Lisp不同.

[注意:有一个" 模板Haskell "可以让你像在Lisp中一样编写宏,但严格来说你永远不需要它.


来自Don Stewart引用的Conor McBride:*'我喜欢将类型视为扭曲我们的引力,因此我们需要前往[编写正确程序]的方向变得"下坡".*类型系统使其变得非常简单编写正确的程序...请参阅[这篇文章](https://plus.google.com/115274377971493973150/posts/jMqzaxPEnrd)及其重新分享.
取出Haskell的currying.你能用Haskell中剩下的东西来实现它吗?另一个例子:假设Haskell不支持模式匹配,你可以自己添加它而不必让GHC的开发人员支持它吗?在CL中,您可以使用宏来随意扩展语言.我认为这就是为什么CL语言自90年代标准以来没有改变的原因,而Haskell似乎在GHC中有一个永无止境的扩展通道.
高阶函数不能代替宏,事实上,CL由于某种原因都有.CL中宏的真正强大之处在于它们允许开发人员引入新的语言功能,以帮助更好地表达问题的解决方案,而无需等待Haskell或Java中的新版本语言.例如,如果Haskell具有这种能力,那么Haskell作者就不需要编写GHC扩展,它们是否可以由开发人员自己实现为宏.

2> Matthias Ben..:

首先,不要担心失去动态类型等特定功能.由于您熟悉Common Lisp,这是一种设计精良的语言,我假设您已经意识到语言不能简化为其功能集.这一切都是关于一个连贯的整体,不是吗?

在这方面,Haskell的亮度与Common Lisp一样明亮.它的功能相结合,为您提供了一种编程方式,使代码非常简短和优雅.通过更复杂(但同样,更难以理解和使用)的概念,如monad和箭头,可以减轻宏的缺乏.静态类型系统增加了你的能力,而不是像大多数面向对象语言那样妨碍你.

另一方面,Haskell中的编程比Lisp更不具有交互性,而像Lisp这样的语言中存在的大量反射不适合Haskell预设的世界静态视图.因此,您可以使用的工具集在两种语言之间存在很大差异,但很难相互比较.

我个人更喜欢Lisp的编程方式,因为我认为它符合我工作的方式.但是,这并不意味着你也必然会这样做.


你能详细说明一下"在Haskell中编程的交互性要低得多".GHCi真的没有提供您需要的一切吗?
@JohannesGerer:我还没有尝试过,但据我所知,GHCi不是运行映像的shell,你可以在运行时重新定义和扩展整个程序的任意部分.此外,Haskell语法使得以编程方式在repl和编辑器之间复制程序片段变得更加困难.

3> Herrmann..:

在Haskell中对元编程的需求比在Common Lisp中少,因为很多可以围绕monad构建,增加的语法使得嵌入式DSL看起来不像树一样,但是ShreevatsaR,甚至Liskell(Haskell语义+ Lisp)都提到了模板Haskell.语法)如果你喜欢括号.



4> Hibou57..:

关于宏,这里有一个讨论它的页面:Hello Haskell,Goodbye Lisp.它解释了Haskell中不需要宏的观点.它附有一个简短的比较例子.

需要LISP宏以避免评估两个参数的示例情况:

(defmacro doif (x y) `(if ,x ,y))

示例情况,其中Haskell没有系统地计算两个参数,而不需要像宏定义那样:

doif x y = if x then (Just y) else Nothing


这是一种常见的误解.是的,在Haskell中,懒惰意味着当您想要避免评估表达式的某些部分时不需要宏,但这些只是所有宏用法中最微不足道的子集.Google为"The Perine Before Perl"进行了一场演讲,演示了一个无法用懒惰做的宏.另外,如果你*需要一些要严格的话,那么就不能把它作为一个函数 - 反映出Scheme的`delay`不能成为一个函数.
好的,我放弃了.显然你对DSL的定义是"宏的参数",所以我的懒惰的Scheme例子不是DSL,尽管它在句法上与原始同构(`automaton`变成'letrec`,`:`变成`accept`,` - >"在这个版本中变得一无所有".随你.
@Eli Barzilay:我觉得这个例子不太令人信服.这是幻灯片40的完整,简单的Haskell翻译:http://pastebin.com/8rFYwTrE
@Eli Barzilay:我根本不明白你的回答.`accept`*是*(E)DSL.`accept`函数是前面几页中概述的宏的类似函数,`v`的定义与幻灯片40中Scheme的`v`的定义完全平行.Haskell和Scheme函数计算相同的东西相同的评估策略.最好的情况是,宏允许您将更多程序结构公开给优化器.你很难说这是一个例子,其中宏以一种不被懒惰评估复制的方式增加语言的表达能力.
@Eli Barzilay:在一个假想的懒惰方案中,你可以这样写:http://pastebin.com/TN3F8VVE我的一般主张是这个宏很少给你买:语法略有不同,优化器更容易(但它不会对"足够聪明的编译器"来说很重要.作为交换,你把自己困在一种无言的语言中; 你如何定义一个匹配任何字母而不列出所有字母的自动机?另外,我不知道你在"在所有子列表中使用它"或"在具有自己的范围的地方所需的使用"中的含义.
@Reid Barton:嗯?该论文的主要观点是创建一个*宏*,它实际上是一个小型DSL,用于指定被"编译"为Scheme代码的自动机.你的代码OTOH是一种代码的简单翻译 - 但是(a)它使用Shriram在开始时谈到的表查找,更重要的是,(b)你使用普通的Haskell,以及结果仍然没有接近定义这样的DSL.AFAICT,这是唯一能证明的"当你可以在表格中使用函数值时,编写这样的代码很容易".即,与宏没有多大关系.
我没有关注这些.首先,是的 - "accept"是完成工作的函数,但它不是DSL,它是一个像所有其他函数一样的函数 - 以及在所有子列表中使用它或者需要使用它的东西.具有自己范围的`正是宏不必要的.至于懒惰的评估 - 你没有以任何重要的方式使用它,所以我不知道整个论证是如何相关的.
里德:(a)一个懒惰的计划不是假设的 - 一个人已经成为Racket的一部分已经有好几年了; (b)宏仍有用的事实有一个很好的暗示; (c)你所写的内容也显示了为什么宏是有用的 - 它*不会*使用一个,因此不是Shriram所谈论的DSL; (d)通过"在子列表中使用它"等我的意思是你对来自实现的"DSL"有一定的要求(例如,使用`accept`) - 这就是为什么它不是*DSL的一个原因;
(e)如果你考虑在惰性语言中添加严格的运算符,那么懒惰使得流控制宏(没有新绑定的那些)冗余的错觉可以被视为假 - 使用这样的运算符需要特殊的形式(和宏) ); (f)另一点:如果Haskell中不需要宏,它们怎么会有它们呢?(甚至在TH之前,CPP也有用途.)
最后,(g)确保你陷入一种"不言而喻的语言" - 整个观点是*DSL* - 而不是GPL.显然,可以编写一个更复杂的宏,它将具有Scheme表达式(如符号的谓词而不是列出所有符号),但这超出了本例中的DSL.

5> Leslie P. Po..:

我是Common Lisp程序员.

在不久前尝试过Haskell之后,我个人的底线就是坚持使用CL.

原因:

动态打字(查看动态与静态打字 - Pascal Costanza基于模式的分析)

可选和关键字参数

统一的homoiconic列表语法与宏

前缀语法(无需记住优先级规则)

不纯,因此更适合快速原型制作

具有元对象协议的强大对象系统

成熟的标准

各种编译器

Haskell确实有自己的优点,并且以一种根本不同的方式做一些事情,但它并没有为我长期削减它.


该论文中没有一个例子(Pascal Costanza,*动态与静态打字 - 基于模式的分析*)适用于Haskell.它们都是特定于Java的(或者更确切地说,特定于["面向对象的编程"](http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html ))我无法看到Haskell中出现的任何问题.同样地,你所有的其他论点都是有争议的:人们也可以说Haskell是"纯粹的,因此更适合快速原型化",前缀语法不是强制性的,它没有广泛的编译器做不同的事情等
那篇论文确实与Haskell完全无关."`dilbert = dogbert.hire(dilbert);``?? 我怀疑很多Haskell程序员甚至可以在不抽搐的情况下阅读它.
请注意,haskell也支持前缀语法,但我会说monad >> =使用它会非常难看.我也不同意杂质是一种祝福:P
我喜欢这个旁注:_我们还没有收集经验数据,这个问题是否会导致现实世界的程序出现严重问题._

6> luntain..:

在Haskell中,您可以定义一个if函数,这在LISP中是不可能的.这是可能的,因为懒惰,允许程序更多的模块化.这篇经典论文:John Hughes 为什么选择FP,解释了懒惰如何增强可组合性.


(defmacro doif(xy)`(if,x,y))
Scheme(两种主要的LISP方言之一)实际上确实有懒惰的评估,尽管它不像Haskell那样默认.
宏与函数不同 - 宏与高阶函数(例如`fold`)不兼容,例如非严格函数*do*.

7> 小智..:

在Lisp中,使用Haskell繁琐(如果可能)的宏可以实现非常酷的事情。以“ memoize”宏为例(请参阅Peter Norvig的PAIP的第9章)。有了它,您可以定义一个函数,例如foo,然后简单地求值(记住'foo),该函数用一个已记忆的版本替换foo的全局定义。在Haskell中使用高阶函数可以达到相同的效果吗?


您可以将foo添加到惰性数据结构中,该值一旦计算就将存储在其中。这实际上是相同的。
不完全(AFAIK),但是您可以通过修改函数(假设它是递归的)以将函数作为参数(!)进行递归调用,而不是简单地通过名称本身进行调用来做类似的事情:http://www.haskell。组织/ haskellwiki /备忘录
推荐阅读
Life一切安好
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有