Haskell是否有缺点或问题?


47

我正在考虑进入Haskell进行下一个(相对琐碎的)个人项目。我处理Haskell的原因是:

  1. 让我沉迷于纯粹的功能语言
  2. 速度。虽然我可以肯定这是有争议的,但分析表明我发现Haskell接近C ++(并且似乎比Erlang快很多)。
  3. 速度。与几乎所有其他服务器相比, Warp Web服务器似乎快疯了

因此,鉴于此,我正在寻找的是Haskell带来的弊端或问题。Web上有大量有关Haskell为什么是一件好事的信息,但是我没有找到很多有关其丑陋方面的主题(除了对语法的牢记,我根本不在乎)。

我正在寻找的示例可能像Python的GIL。直到我真正开始考虑在CPython环境中使用并发性时,这些事情才浮出水面。



26
我听说较少的程序员处理过大脑融化的问题。这是非常昂贵的治疗条件。
ChaosPandion 2012年

1
@FrustratedWithFormsDesigner:感谢您的链接。但是,仍然没有任何关于Haskell的技术缺点的参考。是否可能没有?;)
Demian Brecht 2012年

6
@ChaosPandion:我也听到过同样的话。但是,如果您动脑筋,您是否真的在尝试?;)另外,我不会真的把自己当成一个小程序员,所以我对此并不太担心;)
Demian Brecht 2012年

3
@ChaosPandion:而且大多数健康计划都没有涵盖它。:(
FrustratedWithFormsDesigner 2012年

Answers:


48

我能想到的一些缺点:

  • 由于该语言的性质及其扎根于学术界的根基,因此该社区非常注重数学。如果您是一个务实的人,有时可能会令人不知所措,如果您不说专业术语,那么您将比使用许多其他语言更难。
  • 尽管有数量惊人的库,但是文档通常很简洁。
  • 入门级教程很少,而且很难找到,因此初始学习曲线非常陡峭。
  • 一些语言功能不必要地笨拙;一个突出的例子是记录语法如何不引入命名范围,因此无法在同一模块名称空间内的两种不同类型中使用相同的记录字段名称。
  • Haskell默认为惰性评估,尽管这通常是一件好事,但有时可能会以讨厌的方式咬住您。在非平凡的情况下天真地使用惰性评估会导致不必要的性能瓶颈,而了解幕后的情况并非一帆风顺。
  • 懒惰的评估(尤其是结合了纯度和积极优化的编译器)也意味着您不容易推断出执行顺序;实际上,您甚至都不知道在给定情况下是否确实对某段代码进行了评估。因此,仅因为单步执行代码的用处不大且意义不大,调试Haskell代码需要不同的思维方式。
  • 由于Haskell的纯正性,您不能使用副作用来执行I / O之类的操作;您必须使用monad和“ abuse”惰性评估来实现交互性,并且必须将monadic上下文拖到可能要执行I / O的任何位置。(实际上,从许多方面来说,这都是一个不错的功能,但有时无法进行实用的编码。)

16
实际上,现在有一些非常好的入门书籍可以在线免费获得。了解您的Haskell成就伟大是我读过的最好的初学者编程书籍之一,而Real World Haskell是很好的中间资源。
Tikhon Jelvis'1

1
@TikhonJelvis:这些确实是我发现值得使用的仅有的两个候选人;“ Learn a Haskell”使我感到困惑,“ Real World Haskell”为我工作,但需要一些编程背景。也有“ Haskell的柔和介绍”,但是几乎是柔和的,特别是如果您缺乏数学背景。
tdammers

我使用“ Haskell简介”和“真实世界Haskell”。两者的结合给了我很多有用的信息。我的工作水平足以应付一个非同凡响的项目,但不幸的是我没有太多时间来做。
乔治

9
“如果您是一个务实的人……”:有时使用面向数学的语言是一个非常务实的决定,如果这样做可以避免以后出现很多错误修复问题。当然,您应该始终在使用工具节省多少时间和学习如何使用该工具之间花费多少时间之间找到平衡。
Giorgio 2013年

Monad会(并使用其他语言)以严格的语言工作完全相同。您绝对不要“滥用”懒惰的评估来实现交互性,在Haskell中编写严格的交互程序是微不足道的。
分号

19

Haskell的大多数缺点(以及Haskell的大部分缺点)都来自于两个定义特征:惰性和纯粹的功能。

懒惰使人们很难对性能进行推理。特别是对于那些不习惯懒惰的人,但是即使对于有经验的Haskellers,在某些情况下也很难看到懒惰会如何影响性能。

懒惰还意味着不使用Criterion之类的库就很难创建准确的基准。

纯粹是功能性的,这意味着每当您需要使用可变数据结构时(在没有可变数据结构的情况下都无法实现所需性能的情况下,尽管由于GHC的优化器的出现并不像您想像的那么频繁),您将卡在IO(或ST)单子中,这使代码更加繁琐。

因为您提到速度是您的目标之一,所以我应该指出,手动优化的Haskell代码与编写时没有过多考虑性能的Haskell代码之间在性能上常常存在巨大差异(比其他语言要多)。手动优化的Haskell代码通常很难看(尽管我认为在大多数其他语言中也是如此)。


1
纯粹的功能实际上是一种卖点,而不是缺点。语言是“惰性”毫无意义,惰性与严格是类型问题,惰性和严格类型都有其用途。(因此,Haskell缺乏严格的类型同样会受到困扰,就像大多数语言由于没有惰性类型而受到损害一样。)Haskell的主要缺点是其糟糕的模块系统(模块不是一流的),事实类型类实际上破坏了模块化( “每个类型一个实例”规则强制编译器保留类型类实例的全局列表)。
pyon 2013年

21
“而且手动优化的Haskell代码通常很难看(尽管我认为在大多数其他语言中也是如此)。” 这个。当人们想要展示Haskell的精致之处时,他们会发布简短的代码,不幸的是,如果运行类似生产的数据量,则会给您带来非常糟糕的性能。当人们想证明“ Haskell和C ++一样快”时,他们会发布复杂且难以阅读的代码,这仍然比C
语言中

12

我不是Haskell专家:我已经学习了基础知识,但不幸的是,我还没有机会在Haskell上进行一些严肃的项目(我想,因为我非常喜欢这种语言)。

但是,据我所知以及与从事函数式编程的人们的讨论,Haskell可能不是当您想要实现图形算法时的最佳解决方案,例如在图形中执行并执行图结构上的许多局部更改。

由于图通常没有递归结构,因此我认为最好的方法是使用结构和它们之间的指针构建图的一个副本(例如,在C ++中可以这样做),然后通过更改指针来操纵该副本,创建或销毁节点,等等。

我不知道在Haskell中如何正确处理此类数据结构和操作,因为据我所知,在Haskell中不可能使用上述表示/方法。本文简要讨论了Haskell中图算法的一些问题

编辑

我最近与函数式编程专家进行了交谈,他证实在Haskell中高效实现某些图形算法可能非常棘手:像在C或C ++中那样处理指针可以更快。


在纯函数世界中有关图操作/遍历的有趣注释(和链接)。没考虑过。
Demian Brecht 2012年

7
纯函数图算法是一个有趣的话题。惯用的解决方案是通过用纯功能词典替换指针来模拟命令式表示,例如将给定顶点映射到它具有边的顶点集合。但是,除非使用弱字典,否则将泄漏内存,因为无法收集无法访问的子图并且没有已知的纯功能弱字典。归根结底,最先进的纯功能解决方案既复杂又效率低下!
乔恩·哈罗普

1
另一方面,众所周知,图算法可能很难调试,持久性数据结构可以缓解此问题……
乔恩·哈罗普

我想知道是否有可能开发图形数据类型(遵循ByteString的想法:高效的内部表示形式加上转换/访问功能)。使用monad可以使这样的图形可变。当然,这将解决表示图形的问题,而不是实现图形算法的问题。
Giorgio

DAG是一回事。对于其他所有事情,您都可以利用懒惰和“打结”。
丹尼尔2015年

4

Haskell的缺点是它与众不同。与更常教授或谈论的语言相比,这是更大的一步,因此学习曲线会更大。它也不太流行,如果您遇到困难,它可能会限制帮助的可用性。这些确实不是主要缺点。

潜在的缺点之一是它是一种功能语言,因此它在某些问题领域中的用处不大,但对于面向对象的语言也是如此。通常,语言至少在相对流行的语言中没有学习曲线之外的真正负面条件。只要图灵语言完整,理论上它就可以做到。


3
图灵完整性是一个红鲱鱼。计算理论=实际编程。

1
@delnan,这就是我从理论上说的原因
Ryathal 2012年

2
据说Haskell对其用处不大的那些“问题域”是什么?
Andres F.

3
确实,社区规模较小,但实际上却活跃得多。我认为freenode上的#haskell频道在语言渠道中的流行程度仅落后于#python,并且在SO上回答有关Haskell的问题令人惊讶地具有竞争性:)
Tikhon Jelvis 2012年

@AndresF。-我不会说“没什么用”,但是Haskell在某些方面肯定仍处于起步阶段:1)重型DP-我编写了一个简单的背包算法,从字面上震惊于如何太慢了 那是使用盒装数组,所以我预计会有一些开销,但是比我预期的要差得多。2)大型非平凡游戏-AFRP尚处于起步阶段,因此没有特别好的框架,而且效果仍然很难预测。我们要看到Haskell版本的Doom还要很长时间。(frag不计数-它没有AI。)
rtperson 2012年

0

因此,鉴于此,我正在寻找的是Haskell带来的弊端或问题

“ Haskell问题”往往出现在某些领域。Haskell是用于应用程序编程的一种很棒的语言,编写起来比其他任何事情都要令人愉快。当您尝试做一些没有很好支持的事情时,这些问题往往会出现,例如:

  • 交叉编译。GHC可以作为交叉编译器构建,但是过程相当复杂。
  • 嵌入式应用程序。Haskell通过垃圾回收器进行内存管理,因此这并不奇怪。
  • 速度。Haskell不如Rust快,尽管在大多数情况下,它的竞争都相当不错。它在很大程度上取决于应用程序域-纯粹的计算得到了很好的优化,但是类似“将文件读入缓冲区并计算行数”之类的东西在Haskell中很难表达。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.