当前位置: 首页 > 工具软件 > Cloud Haskell > 使用案例 >

ie css hask_我们功能性的未来,或者:我如何学会不再担心和爱Haskell

方英耀
2023-12-01

ie css hask

This fall, I had the chance to dive headfirst into functional programming languages. It’s not a journey for the dabbler or the faint of heart, but it’s one that’s worthwhile.

今年秋天,我有机会首先深入研究函数式编程语言。 这不是一个涉猎者或胆小的人的旅程,但这是值得的。

I’d been aware of functional programming and Haskell in particular for some time, but my attempts to learn it had been less than successful. The problem wasn’t lack of resources; there are some good ones out there, e.g., Learn You A Haskell For Great Good and What I Wish I Knew When Learning Haskell. Maybe it was the novelty of functional programming to me or my lack of dedication, but even after substantial effort, I still couldn’t understand the first line of code in our Ludwig DSL compiler. It was disappointing.

一段时间以来,我一直对函数式编程特别是Haskell有所了解,但是我尝试学习它的尝试并不成功。 问题不在于缺乏资源。 有一些不错的方法,例如, 学习Haskell带来的好处以及学习Haskell时我希望知道的东西 。 也许这对我来说是函数式编程的新颖性,还是我缺乏奉献精神,但是即使经过大量的努力,我仍然无法理解Ludwig DSL编译器中的第一行代码。 真令人失望。

Programming languages aren’t new to me. Having recently completed a Ph.D. in computational fluid dynamics, my “higher-level” languages were C, CUDA, and Fortran. I picked up Python and Go—two primary languages at Fugue—when I joined the team in 2014. Shortly after, several Haskell programmers came on board to design our Ludwig DSL and write its compiler. (Fugue’s users declare infrastructure using this new DSL.)

编程语言对我而言并不陌生。 最近完成了博士学位。 在计算流体动力学方面,我的“高级”语言是C,CUDA和Fortran。 当我于2014年加入团队时,我在Fugue中学习了Python和Go这两种主要语言。不久之后,几名Haskell程序员加入了我们的设计路德维希DSL并编写其编译器。 ( Fugue的用户使用此新的DSL声明基础结构。)

After attending the ICFP and CUFP in Vancouver, Canada, and participating in a week of on-site training by Well-Typed, I’ve become reasonably confident that, despite some acute challenges, the future of our industry will be tied to functional programming.

在参加了加拿大温哥华的ICFPCUFP并参加了Well-Typed的为期一周的现场培训之后,我已经变得相当有信心,尽管有一些严峻的挑战,我们行业的未来仍将与功能编程联系在一起。 。

收养之路 (The Path to Adoption)

The community is aware of the difficulty of adoption. Amanda Laucher gave the extraordinary CUFP keynote focusing on the battle for getting functional programming accepted in the industry.

社区意识到收养的困难。 阿曼达·劳彻(Amanda Laucher)作了非凡的CUFP主旨演讲,重点讨论了使功能编程在业界得到认可的斗争。

Functional programming has won all the technical and theoretical battles (at least, most functional programmers think so!), but it’s losing the war on adoption. Pain points, left to the developer to sort out, include issues with tooling, documentation, learning resources, and a concise and uniform standard library. Simon Marlow’s talk on Facebook’s high-profile move to Haskell echoed these themes. The project required as much time developing tools and educational resources as it did building the actual product.

函数式编程赢得了所有的技术和理论战(至少,大多数函数式程序员都这么认为!),但是它却在采用方面失去了战斗。 留给开发人员解决的痛点包括工具,文档,学习资源以及简洁统一的标准库等问题。 西蒙·马洛(Simon Marlow)关于Facebook高调转移到Haskell 演讲也呼应了这些主题。 该项目与构建实际产品一样,需要大量时间来开发工具和教育资源。

The rapid acceptance of Stack and Stackage does show the community’s ability to create great solutions that solve developers’ problems. Specifically, Stack tackled two major problems with using Cabal, a system for building and packaging Haskell libraries and programs: (1) library compatibility through long term support releases, and (2) more robust sandboxing and caching to dramatically reduce project build times. Stackage gives a self-consistent LTS release, but for only 4-6 months. More tools like these and their continued improvement likely will have a positive impact on expanding Haskell’s use and on adoption of functional programming in general, but we’ve got to move forward assertively with their development.

StackStackage的Swift接受确实显示了社区具有创建解决开发人员问题的出色解决方案的能力。 具体而言,Stack使用Cabal解决了两个主要问题, Cabal是用于构建和打包Haskell库和程序的系统:(1)通过长期支持版本实现库兼容性,以及(2)更强大的沙箱和缓存功能,以大大减少项目的构建时间。 Stackage可提供一致的LTS发行,但仅持续4-6个月。 像这样的更多工具以及它们的不断改进,可能会对扩大Haskell的使用范围和总体上对函数式编程的采用产生积极影响,但是我们必须在其开发方面果断地前进。

In my post-conference efforts to learn, I worked to a general knowledge of Haskell when I started to port some of my smaller projects to it. I made progress and would show my Haskell co-workers my code. Their support was incredible, their advice focused and constructive. However, I found that a lot of mistakes kept coming back to this: not using the correct libraries. In particular, there were several libraries that implemented a printf-like function including Text.Printf on Hackage. Coming from Go’s standard library, I expected the top search result with a canonical name to be what I was looking for. You can imagine my shock when I found out, not only was the Text.Printf library not used often or regarded as the best (that would be Text.Format), but it was not type safe! By formatting a string in my program, I was giving up much of the safety I thought I was gaining by using Haskell! Finding the right libraries and functions continues to be an issue, whether it’s array and vector for arrays or the small army of fold functions scattered about.

在会议后的学习中,当我开始将一些较小的项目移植到Haskell时,我就对Haskell有了一个一般的了解。 我取得了进步,并将向我的Haskell同事展示我的代码。 他们的支持令人难以置信,他们的建议重点突出且富有建设性。 但是,我发现很多错误会再次归结于此:没有使用正确的库。 特别是,有几个库实现了Text.Printf printf的功能,包括Text.Printf上的Text.Printf 。 来自Go的标准库,我希望带有标准名称的顶部搜索结果是我想要的。 您可以想象得到的震惊,不仅是Text.Printf库不经常使用或被认为是最好的库(将是Text.Format ),而且类型也不安全 ! 通过在程序中格式化字符串,我放弃了许多我认为通过使用Haskell获得的安全性! 寻找合适的库和函数仍然是一个问题,无论是array的数组还是array vector ,还是散布着小数目的折叠函数。

生活中有一些保证 (There Are Some Guarantees in Life)

Despite obstacles and hesitations, the benefits of functional programming are immense. The key is this: language guarantees make code more robust, help to mitigate errors, and eliminate entire classes of bugs.

尽管有障碍和犹豫,函数式编程的好处是巨大的。 关键是:语言保证可以使代码更健壮,有助于减少错误并消除所有类别的错误。

A guarantee provided by a functional programming language is an assurance like “data is immutable.” If you pass data into a function, you don’t have to worry about that function modifying that data. It’s impossible. One big class of bugs that occurs in other languages (Python, Go, Java, etc.) is that you’ll pass in a data structure to a function and that function may change the data structure in an unexpected way.

功能编程语言提供的保证是一种保证,例如“数据是不可变的”。 如果将数据传递给函数,则不必担心该函数会修改该数据。 不可能。 在其他语言(Python,Go,Java等)中发生的一大类错误是,您将数据结构传递给函数,而该函数可能会以意想不到的方式更改数据结构。

In addition, many bugs can be traced back to missing or incorrect error handling code. Haskell has language features to eliminate this type of bug. Rather than handling errors, exceptions, and logic in the same piece of code, Haskell separates error from logic by placing them in contexts (more technically referred to as monads). Contexts completely describe how to process invalid input, freeing the logic to only worry about valid input.

此外,许多错误可以追溯到缺少或不正确的错误处理代码。 Haskell具有消除此类错误的语言功能。 Haskell不在同一代码中处理错误,异常和逻辑,而是通过将错误置于上下文中(在技术上更称为monads )来将错误与逻辑分离。 上下文完全描述了如何处理无效输入,从而释放了仅担心有效输入的逻辑。

In most languages, if a nullable value is being passed around, it is up to each function to check whether that particular value is null and take the appropriate action. If a function developer forgets this check, an error may go uncaught and produce undesirable results. John Carmack made salient points when he said:

在大多数语言中,如果传递了可为空的值,则由每个函数来检查该特定值是否为空并采取适当的措施。 如果功能开发人员忘记了此检查,则可能无法捕获错误并产生不良结果。 约翰·卡马克(John Carmack)指出:

everything that is syntactically legal, that the compiler will accept, will eventually wind up in your codebase. and that’s why i [sic] think that static typing is so valuable, because it cuts down what can make it past those hurdles.

编译器将接受的所有语法上合法的内容最终都将出现在您的代码库中。 这就是我[sic]认为静态类型如此有价值的原因,因为它减少了使它克服那些障碍的原因。

Mistakes and lapses will make it into your code base. With Haskell, a nullable value can be wrapped in a Maybe context, which indicates that there may be a value or Nothing. The functional nature of Haskell allows developers to write functions that act on values without worrying whether or not the values are actually there. The definition of Maybe provides the check and appropriate action wherever the Maybe context is used.

错误和失误将使其融入您的代码库。 使用Haskell,可以在Maybe上下文中包装可为空的值,这表示可能存在一个值或Nothing 。 Haskell的功能本质允许开发人员编写对值起作用的函数,而不必担心值是否实际存在。 的定义Maybe提供的任何地方的检查,并采取适当的行动Maybe被用于上下文。

That last statement is incredibly powerful. Now instead of depending on multiple developers to handle corner cases uniformly across large codebases, the error handling is defined once for the context. The definition carries across every use of the context by every function without developers needing to worry.

最后的声明非常强大。 现在,不再依赖多个开发人员在大型代码库中统一处理极端情况,而是为上下文定义了一次错误处理。 该定义涵盖了每个函数对上下文的每次使用,而开发人员无需担心。

Predefined contexts including Maybe for nullable values and Either for multiple types of values or error support can get developers quite far. Each of these contexts contains the complete description of how to handle the corner cases when a function is applied. It’s easy to provide custom contexts as well.

预定义的情境,包括Maybe为空的值,并Either多个类型的值或错误的支持可以让开发者很远。 这些上下文中的每一个都包含有关在应用函数时如何处理极端情况的完整描述。 提供自定义上下文也很容易。

With the contexts provided in Haskell and other functional programming languages, developers can eliminate a type of bug we find occasionally at Fugue. As much as we try to avoid it, we occasionally find an access to a None in Python or an ignored non-nil error in Go. Using contexts in a functional language eliminates this class of errors. A developer cannot forget to add error handling to a new piece of logic, because it has already been handled by the context.

利用Haskell和其他功能编程语言提供的上下文,开发人员可以消除在Fugue中偶尔发现的一种错误。 尽我们所能避免,我们偶尔会在Python中找到对None的访问,或者在Go中发现被忽略的nil错误。 在功能语言中使用上下文可以消除此类错误。 开发人员不能忘记将错误处理添加到新的逻辑中,因为上下文已经对其进行了处理。

At Fugue, our product aims to tame the challenges of distributed computing in the cloud, starting with Amazon Web Services. Dealing with eventual consistency and failure is the rule in our product, not the exception. Fugue requires a significant amount of error checking and handling when it interacts with remote services. We rely on discipline to limit the amount of code that touches AWS and to provide the proper error handling.

在Fugue,我们的产品旨在从Amazon Web Services开始,应对云中分布式计算的挑战。 处理最终的一致性和失败是我们产品中的规则,并非例外。 当Fugue与远程服务交互时,需要大量的错误检查和处理。 我们依靠纪律来限制接触AWS的代码量并提供适当的错误处理。

But what happens if we find AWS interactions scattered throughout our code in places they should not be? In Python and Go, we need to trust that each function avoids performing these interactions. There is no way to know if each does other than inspecting the source code. This creates huge headaches for a developer using this function, especially if that person doesn’t know that it has an external (non-functional) dependency.

但是,如果我们发现AWS交互散布在整个代码中不应该出现的地方,会发生什么? 在Python和Go中,我们需要相信每个函数都避免执行这些交互。 除了检查源代码外,没有其他方法可以知道每个人是否都在做。 这给使用此功能的开发人员带来了巨大的麻烦,特别是如果该人不知道它具有外部(非功能)依赖关系时。

In Haskell, any external interaction is placed inside an IO context. IO is used in Haskell to show that the associated value is the result of a state mutation. The mutation can be internal (e.g., mutating a data structure, which is rare in functional programming) or external (e.g., file or network access). As with the other contexts, a developer can still write functions that aren’t concerned with the fact that the value came from IO. However, the results stay in the context. It becomes very difficult to hide the fact that a function has external dependencies—this can be done for those brave enough to have unsafePerformIO in a pull request. So, the possibility of a bug from a hidden mutation drops significantly in functional languages because of a context around mutations.

在Haskell中,任何外部交互都放置在IO上下文中。 在Haskell中使用IO来表明相关值是状态突变的结果。 突变可以是内部的(例如,对数据结构进行突变,这在功能编程中很少见)或外部的(例如,文件或网络访问)。 与其他上下文一样,开发人员仍可以编写与价值来自IO无关的函数。 但是,结果保留在上下文中。 隐藏一个函数具有外部依赖关系这一事实变得非常困难-对于那些足够勇敢在pull请求中具有unsafePerformIO人来说,可以做到这一点。 因此,在功能语言中,由于围绕突变的情况,隐藏突变导致错误的可能性大大降低。

Share

分享

Twitter

推特

Reddit

Reddit

Google+

Google+

Facebook

脸书

翻译自: https://www.pybloggers.com/2016/01/our-functional-future-or-how-i-learned-to-stop-worrying-and-love-haskell/

ie css hask

 类似资料: