Haskell有什么大惊小怪的?

我知道有几个程序员在他们之间一直在讨论Haskell,所以大家似乎都喜欢这种语言。 擅长哈斯克尔似乎有点像天才程序员的标志。

有人可以给出几个Haskell的例子,说明为什么它如此优雅/优越?

对于我而言,以及我在Haskell上学习了一个月之后,我认为是事实,函数式编程以一种有趣的方式扭曲了你的大脑:它迫使你以不同的方式思考熟悉的问题:而不是循环,思考在地图和折叠和filter等。一般来说,如果你有一个以上的问题的angular度来看,它可以让你更好地推理这个问题,并根据需要切换视点。

另一个关于Haskell真正整洁的东西是它的types系统。 这是严格的types,但types推理引擎使它感觉像一个Python程序,神奇地告诉你,当你做了一个愚蠢的types相关的错误。 Haskell在这方面的错误信息有些欠缺,但是随着你对这门语言的熟悉,你会对自己说:打字应该是这样的!

这就是说服我学习Haskell 例子(我很高兴我做了这个)。

-- program to copy a file -- import System.Environment main = do --read command-line arguments [file1, file2] <- getArgs --copy file contents str <- readFile file1 writeFile file2 str 

好吧,这是一个简短的,可读的程序。 从这个意义上说,它比C程序更好。 但是,与一个结构非常类似的Python程序有什么不同呢?

答案是懒惰的评价。 在大多数语言(甚至是一些function语言)中,像上面那样构造的程序会导致整个文件被加载到内存中,然后再以新的名字写出来。

哈斯克尔是“懒惰”的。 它不计算的东西,直到它需要,并通过扩展计算的东西,它永远不需要。 例如,如果您要删除writeFile行,Haskell不会从文件中读取任何内容。

实际上,Haskell意识到writeFile依赖于readFile ,所以能够优化这个数据path。

虽然结果是依赖于编译器的,但运行上述程序时通常会发生的情况是:程序读取第一个文件的块(如8KB),然后将其写入第二个文件,然后从第一个文件读取另一个块文件,并将其写入第二个文件,依此类推。 (尝试运行strace !)

…看起来很像文件副本的有效C实现。

所以,Haskell可以让你编写简洁易读的程序 – 通常不会牺牲很多性能。

我必须补充的另一件事是,Haskell只是很难写出错误的程序。 惊人的types系统,缺乏副作用,当然还有Haskell代码的紧凑性,至less可以减less三个错误:

  1. 更好的程序devise。 复杂性降低导致更less的逻辑错误。

  2. 紧凑的代码。 存在的错误线较less。

  3. 编译错误。 许多错误只是无效的Haskell

Haskell不适合每个人。 但是每个人都应该试试看。

你有点问错了问题。

Haskell不是一种语言,你可以看几个很酷的例子,然后去“啊,我现在看到了, 就是它的好处!”

更像是,我们拥有所有这些其他的编程语言,而且它们或多或less都是相似的,然后就是Haskell,它是一个完全不同的古怪的方式,一旦习惯了这个古怪的东西,它就完全可怕了。 但问题是,适应这种古怪需要相当长的一段时间。 Haskell与几乎任何其他甚至半主stream语言都有所不同:

  • 懒惰的评价
  • 没有任何副作用(一切都是纯粹的,IO /等通过monads发生)
  • 令人难以置信的performance静态types系统

以及与许多主stream语言不同的其他方面(但有些共享):

  • 实用
  • 有意义的空白
  • types推断

正如其他一些海报所回答的,所有这些function的结合意味着您可以用完全不同的方式来思考编程。 所以很难想出一个能够与Joe主stream程序员充分沟通的例子(或者一组例子)。 这是一个体验的事情。 (举一个比喻,我可以给你看我1970年中国之行的照片,但是看完照片之后,你还不会知道那段时间住在那里的感觉,同样的,我可以给你看一个Haskell 'quicksort',但是你仍然不知道做一个Haskeller意味着什么。)

让Haskell真正与众不同的是,它在devise中加强了函数式编程。 你可以用几乎任何语言的function风格进行编程,但是在第一个方便的时候放弃这一点太容易了。 Haskell不允许你放弃函数式编程,所以你必须把它的逻辑结论,这是一个更容易理解的最终程序,并回避了一类最棘手的错误。

在编写真实世界使用的程序时,可能会发现Haskell缺乏一些实用的方式,但是最终的解决scheme对于认识Haskell来说更好。 我绝对还没有到现在,但到目前为止,学习Haskell比Lisp更有启发性,Lisp在大学里。

部分问题是纯度和静态打字使得并行性和积极的优化结合在一起。 并行语言现在很热,多核有点破坏性。

与几乎任何通用语言相比,Haskell为您提供了更多的并行select,以及快速的本地代码编译器。 这种平行样式的支持真的没有竞争:

  • 通过线程火花的半隐式并行
  • 明确的线程
  • 数据并行arrays
  • 演员和消息传递
  • 交易记忆

所以如果你关心如何使你的多核心工作,Haskell有话要说。 Simon Peyton Jones的关于Haskell并行和并发编程的教程是一个很好的开始。

我花了去年的时间学习了Haskell,并且写了一个相当庞大而复杂的项目。 (该项目是一个自动化的期权交易系统,从交易algorithm到分析和处理低水平,高速的市场数据馈送都是在Haskell中完成的)。它更加简洁明了,易于理解适当的背景)比Java版本,以及非常强大。

可能对我来说,最大的胜利就是通过诸如单声道,单声道等模块化控制stream的能力。 一个非常简单的例子就是Ordering monoid; 在一个expression式如

 c1 `mappend` c2 `mappend` c3 

其中c1等返回LTEQGT ,返回EQ c1使expression式继续,评估c2 ; 如果c2返回LTGT ,即整体的值,并且c3不被评估。 这样的事情在单向消息生成器和parsing器等事物中变得相当复杂和复杂,在这些事物中,我可能会携带不同types的状态,具有不同的中止条件,或者可能希望能够决定是否中止真正意味着“没有进一步处理”或意思是“最后返回一个错误,但继续处理收集更多的错误信息”。

这一切都需要一些时间,可能还需要一些努力来学习,因此对于那些还不知道这些技术的人来说,很难做出令人信服的论证。 我认为Monads的所有教程都给出了一个非常令人印象深刻的演示,但是我不希望任何不熟悉这些材料的人在第一次,甚至第三次仔细阅读时就已经“知道”了。

无论如何,Haskell还有很多其他的好东西,但是这是我没有经常提到的主要原因之一,可能是因为它比较复杂。

软件事务内存是处理并发性的一个很酷的方法。 它比消息传递更灵活,不像互斥锁那样容易出现死锁。 GHC的 STM实施被认为是最好的之一。

对于一个有趣的例子,你可以看看: http : //en.literateprograms.org/Quicksort_(Haskell)

有趣的是看各种语言的实现。

使Haskell如此有趣以及其他function语言的事实是,你必须对如何编程有不同的思考。 例如,您通常不会使用for或while循环,但会使用recursion。

如上所述,Haskell和其他函数式语言擅长并行处理和编写应用程序以在多核上工作。

在处理algorithm或math问题时,我发现非常酷的一件事是Haskell对计算的固有的懒惰评估,这只是由于其严格的function性质才有可能。

例如,如果你想计算所有的素数,你可以使用

 primes = sieve [2..] where sieve (p:xs) = p : sieve [x | x<-xs, x `mod` p /= 0] 

结果实际上是一个无限的列表。 但是Haskell会从右边评估它,所以只要你不想做一些需要整个列表的东西,你仍然可以使用它,而不会让程序陷入无穷无尽,比如:

 foo = sum $ takeWhile (<100) primes 

其中所有素数都小于100.这很好,原因有几个。 首先,我只需要编写一个生成所有素数的素数函数,然后我就准备好使用素数。 在面向对象的编程语言中,我需要一些方法来告诉函数在返回之前应计算多less个素数,或者用对象模拟无限列表行为。 另一件事是,一般来说,你最终编写代码来expression你想要计算的东西,而不是以什么顺序来评估东西 – 而是编译器为你做的。

这不仅对于无限列表很有用,实际上,在没有必要评估的情况下,它一直在使用,而且一直都在使用。

我不能举一个例子,我是一个OCaml的人,但是当我处于和你一样的状况时,好奇心就会持续下去,我不得不下载一个编译器/解释器, 你可能会更多地学习一个给定的function语言的长处和短处。

我同意其他人的看法,看一些小例子不是炫耀Haskell的最好方式。 但是我会给一些。 这是欧拉项目问题18和67的一个闪电般的解决scheme,它要求您find从底部到三angular形顶点的最大总和path:

 bottomUp :: (Ord a, Num a) => [[a]] -> a bottomUp = head . bu where bu [bottom] = bottom bu (row : base) = merge row $ bu base merge [] [_] = [] merge (x:xs) (y1:y2:ys) = x + max y1 y2 : merge xs (y2:ys) 

这是Lesh和Mitzenmacher的BubbleSearchalgorithm的一个完整的,可重用的实现。 我用它将大型媒体文件打包在DVD上进行存档,不浪费:

 data BubbleResult io = BubbleResult { bestResult :: o , result :: o , leftoverRandoms :: [Double] } bubbleSearch :: (Ord result) => ([a] -> result) -> -- greedy search algorithm Double -> -- probability [a] -> -- list of items to be searched [Double] -> -- list of random numbers [BubbleResult a result] -- monotone list of results bubbleSearch search p startOrder rs = bubble startOrder rs where bubble order rs = BubbleResult answer answer rs : walk tries where answer = search order tries = perturbations p order rs walk ((order, rs) : rest) = if result > answer then bubble order rs else BubbleResult answer result rs : walk rest where result = search order perturbations :: Double -> [a] -> [Double] -> [([a], [Double])] perturbations p xs rs = xr' : perturbations p xs (snd xr') where xr' = perturb xs rs perturb :: [a] -> [Double] -> ([a], [Double]) perturb xs rs = shift_all p [] xs rs shift_all p new' [] rs = (reverse new', rs) shift_all p new' old rs = shift_one new' old rs (shift_all p) where shift_one :: [a] -> [a] -> [Double] -> ([a]->[a]->[Double]->b) -> b shift_one new' xs rs k = shift new' [] xs rs where shift new' prev' [x] rs = k (x:new') (reverse prev') rs shift new' prev' (x:xs) (r:rs) | r <= p = k (x:new') (prev' `revApp` xs) rs | otherwise = shift new' (x:prev') xs rs revApp xs ys = foldl (flip (:)) ys xs 

我确定这段代码看起来像随机的乱码。 但是,如果您阅读Mitzenmacher的博客条目并理解algorithm,您会惊讶于可以将algorithm打包到代码中,而无需说明您正在search的内容。

根据你的要求给了你一些例子,我会说, 开始欣赏Haskell最好方法是阅读这篇文章,它给了我编写DVD打包器所需的想法: 为什么函数式编程很重要 John Hughes。 这篇文章实际上早于Haskell,但是它能够很好的解释一些让Haskell这样的人的想法。

我发现,对于某些任务,我使用Haskell非常高效。

原因是因为语法简洁和易于testing。

这是函数声明的语法是这样的:

foo a = a + 5

这是我能想到定义一个函数的最简单的方法。

如果我写反面

inverseFoo a = a – 5

我可以通过写入来检查它是否是任意随机input的反转

prop_IsInverse :: Double – > Bool
prop_IsInverse a = a ==(inverseFoo $ foo a)

并从命令行调用

jonny @ ubuntu:runhaskell quickCheck +名称fooFileName.hs

这将检查我的文件中的所有属性是通过随机testinginput的一百倍。

我不认为Haskell是一切的完美语言,但是在编写一些函数和testing时,我没有看到任何更好的东西。 如果你的编程有一个math部分,这是非常重要的。

对我来说,Haskell的吸引力是编译器保证正确性的承诺。 即使是纯代码的部分。

我已经写了很多科学的模拟代码,并且如果在我之前的代码中有一个错误,我想了很多次,这会使很多当前的工作失效。

如果你可以在Haskell的types系统中包装头部,我认为这本身就是一个成就。

它没有循环结构。 没有多less语言有这个特点。

我同意那些说function性程序devise使你的大脑从不同的angular度来看节目。 我只是把它作为一个爱好者,但我认为它从根本上改变了我解决问题的方式。 如果不接触到Haskell(在Python中使用生成器和列表parsing),我不认为自己会和LINQ一样有效。

为了传达一个反向的观点:Steve Yegge写道, Hindely-Milner语言缺乏写好系统所需的灵活性 :

HM非常漂亮,完全无用的formsmath意义上。 它很好地处理了一些计算结构; 在Haskell,SML和OCaml中find的模式匹配调度特别方便。 毫不奇怪,它处理一些其他常见和非常可取的构造尴尬充其量,但他们解释说这些情况说你错了,你并不真正需要他们。 你知道吗,哦,设置variables。

Haskell是值得学习的,但它有它自己的弱点。