哈斯克尔的孩子们

2020-09-23 18:21:17

如果我回到4年前,告诉我以前的自己哈斯克尔开始失去光彩,我不会相信的。我在Haskell上长大,我对范畴理论的胃口是由Haskell激发的,我最大的编程项目一直在Haskell,我梦想的工作是在一家使用Haskell的公司工作。

但现在,我发现自己对哈斯克尔不像以前那么兴奋了。什么变了?

我想有几件事。我认为一个主要因素是,Haskell真正擅长的编程类型;即为事物创建抽象的、正确的接口,对我来说不再是一种有趣的编程类型。当我想把从事软件工作作为职业时,一种可以让人难以置信地不重复自己的语言是非常有用的。确保数据交换正确性的类型,或允许访问复杂数据结构的镜头,都非常适合在Web后端实现编译器或复杂的业务逻辑。然而,我现在对软件的兴趣主要是作为一种科学/数学工具。数值算法可以在Haskell中完成,但是它们并没有真正从类型系统中获得多少好处,而且它们也没有很好的库支持。

毫无疑问,Haskell可以用来处理我感兴趣的问题,但是如果要在解决我感兴趣的问题和解决我感兴趣的问题的基础设施之间做出选择,我更愿意解决我感兴趣的问题。我的总体感觉是,对于软件工程师来说,Haskell是一个很棒的工具,但我不想成为一名软件工程师,我想成为一名有时使用计算机的数学家。

但还有另一个原因。虽然我认为Haskell仍然是一门伟大的语言,但现在它已经快30岁了。它设法通过不断增加的扩展列表以及不断变化的最佳实践和库(这本身就是一个问题…)保持新鲜感和相关性。但是,如果我们作为一个程序员社会在任何方面都不能用任何一种具有从头开始的优势的编程语言超越它,那将是非常可悲的。在这篇文章中,我想谈谈这些后续语言,以及我对它们的看法。

令人惊讶的是,Haskell的一大优势是作为一种系统语言。它设法比大多数动态语言快得多,同时允许比传统系统语言(如C语言)高得多的界面(显然)。用Haskell编写的“系统”程序的一个很好的例子是git-attendate。这是一个Git附加功能,增加了对大型文件的跟踪,长期以来一直是我的主要备份系统(我最终决定我不需要它的额外功能,更无缝的解决方案会更好地满足我的需求)。

然而,在2020年,总理系统的语言肯定是铁锈。比较Rust和Haskell的性能是不公平的,因为Haskell是针对性能以外的其他方面进行优化的。也就是说,Rust比Haskell更快、延迟更低,这两点都很重要。然而,与C或C++(我们不讨论Go…)不同的是,它也有一个很好的类型系统。。Rust中的类型系统显然受到Haskell类型系统的很大影响,但是他们也实现了“所有权”,这使得杀手级特性--无垃圾收集的自动内存管理成为可能。

当我第一次开始使用Rust时,我真的很怀念Monads。但事情是这样的。在Haskell中使用了大量的monad,并且阅读了大量关于monad的博客文章后,我了解到,在系统环境中,最好只有一个简单的monad堆栈,该堆栈只由Reader+IO组成(也许偶尔还会有一些Reader+IO和Option)。巨大的单体变压器堆栈通常会带来比它们解决的更多的问题。但Reader+IO实质上是Rust的“默认单元栈”。

Rust还有其他一些杀手级的特性,比如编译成Web汇编的能力(是的,确实有ghcjs,但您真的想使用ghcjs吗?)。它也从一开始就以工业为目标,因此拥有一个更有活力的生态系统。

尽管如此,我认为值得看看Haskell中突出的特性,这些特性最终将走向Rust。

SUM类型(您可能认为这是理所当然的,但是很多语言都没有…。。)。

我认为我们应该认识到铁锈的本质,它是哈斯克尔和哈斯克尔社区的孩子,就像所有好的父母一样,我们应该希望它比上一代做得更好。正如哈斯克尔是形成哈斯克尔的思想一样,“铁锈”的成功也是哈斯克尔的成功。

好的,主流编程语言是很棒的,但有时你只是想为你的东西做一个完美的基于类型的界面,并展示你是一个多么神奇的孩子。或者,有时您真的很关心您的软件是否正确。或者,您想要为编译器的一部分具体化一个受范畴论启发的新设计。如今,与此相关的语言不是Haskell,而是Idris。

在Haskell数组中,大约有六种不同的方式来排序依赖类型(依赖于值的类型,比如长度为n的类型)。我并不完全理解他们中的任何一个,我也完全不清楚他们是如何合作的。想必,有一些博客勾勒出了唯一正确的方法,但…。这很艰难。在Idris中,使用依赖类型似乎非常自然,比如,为什么不能有一个类型参数作为值呢?除了依赖类型之外,在许多方面,Idris也比Haskell干净得多。在Idris2中,它支持线性类型,通过保证没有人会尝试使用旧值,从而允许函数上下文中的可变性。如果我想用一种可以实际与现实世界打交道的语言来使用一个很酷的类型系统(即,不像AGDA或Coq),我会选择Idris,而不是Haskell。

但不可否认,伊德里斯是哈斯克尔的孩子。第一个版本是用Haskell编写的(现在是自托管)。它们在更多方面的相似之处超出了它的价值。说得够多了。

与前两位不同的是,朱莉娅并没有强行进入哈斯克尔的领地。科学计算从来都不是Haskell真正的强项,尽管有一些非常酷的库是用它编写的,比如自动微分的ad,或者自动融合连续数组操作的各种数组处理包。

此外,Julia是一种动态类型的语言。一种肮脏的动态类型语言怎么可能自称是哈斯克尔的孩子呢?

嗯,首先,它窃取了一些很酷的库,并使它们变得更好!Flux是一个神经网络库,本质上只是自动微分+一些不错的实用程序,在我看来,它已经可以与TensorFlow竞争了。Julia还有StaticArray,它将数组的大小集成到类型中,并且Julia也有一些巧妙的融合能力,可以真正快速地进行数组操作。

但是等等,您会问,如果它不是一种静态类型的语言,它怎么能做到这一点呢?嗯,Julia不是一般的动态类型语言。它实际上有一个非常有趣的类型系统,对它的全面讨论超出了本文的范围,而将类型作为编程单元的重点是(多少?)。类似于Haskell(不过现在我稍微扩展了一下)。

然而,我把朱莉娅包括进来的真正原因是,对我个人来说,它已经取代了哈斯克尔,成为研究范畴理论的地方。这是因为观点的转变:Julia没有提供可以嵌入范畴理论的类型系统来指导典型的软件工程任务,而是提供了一个可以高效地执行范畴理论中的计算的系统。具体地说,我说的是Catlab.jl。关于Catlab.jl的讨论也超出了这篇文章的范围,但我鼓励您去看看。

因此,我将Julia视为Haskell的孩子(或者,我可能将Catlab.jl视为Haskell的孩子),因为如果没有Haskell,用范畴论组织计算的想法就不会以同样的方式存在。

如果我能和四年前那个痴迷于哈斯克尔的少年谈谈,我会告诉他要敞开心扉。Haskell在很多方面仍然很棒(我想到的是编译器),但是如果Haskell不能激励优秀的继任者,那么Haskell就不会有什么有价值的想法。互联网上有一些人在谈论哈斯克尔是如何死去的,他们可能是错的,也可能是正确的。我的主要偶像之一斯蒂芬·迪尔(Stephen Diehl)正在与哈斯克尔社区保持距离,因为哈斯克尔在诈骗加密货币上被用作智力上的眼花公子,我认为可能会有一个转折点,哈斯克尔可能会失去令人兴奋的时代精神,因为它从一开始就没有在行业中站稳脚跟,陷入无关紧要的境地。但Haskell将永远活着;它对许多程序员和许多与其实际使用不成比例的语言产生了巨大的影响,它将永远在我的心中占有特殊的位置。