wro*_*yte 5 f# design-patterns functional-programming language-design
我是函数式编程的新手,刚刚遇到了在头部和尾部划分列表的模式。
\n我有Javascript和Python的背景,据我所知,这些语言不采用这种划分,因此它似乎是与函数式编程范式相关的设计,因为像Haskell这样的语言采用了这种划分。例如,在 F# 中(根据Understandingpatternmatchingwithconsoperator),列表是类型的可区分联合
\ntype list<\'T> = // \'\n | Nil\n | Cons of \'T * list<\'T>\nRun Code Online (Sandbox Code Playgroud)\n其中我们有一个 和 的[]并集\xe2\x80\x98a*list<\xe2\x80\x98a>。因此,列表是按设计“划分”的。
头部和尾部的划分列表与函数范式有何关系?它有助于解决哪些问题?我希望能找到一些例子来说明这种划分是有用的和/或需要的。
\n先问它有助于解决什么问题?,询问它来自哪里可能会有所帮助?
但要回答这个问题,它有助于解决什么问题?,答案是:将零个或多个项目作为事物集合来处理的问题。
如果您现在说:但是我们已经为此拥有了集合(或者,在 .NET 中)!IEnumerable<T>,那只是因为您已经处于存在此类抽象的上下文中。
然而,想象一个这些都不存在的世界。
列表,从“缺点列表”的意义上来说,是从首要原则解决“众多”问题的一种方法。
如果您所拥有的只是类似于 lambda 演算的东西,那么您需要弄清楚如何以一致的方式处理许多对象。cons 列表是一种可以从 F 代数定义的数据类型。因此,它是一种基本数据类型 - 有点像逻辑门(如与非门)是计算机电路的基础。
特别是在 Haskell 中,它作为基本集合类型也非常有用,适合 80% 以上的正常使用。在 Haskell 中,您通常可以使用内置的链表 ( []) 数据类型来解决您的问题。
然而,它在 Haskell 中如此有用,还源于 Haskell 是惰性求值的事实。因此,在 Haskell 中,所有链表都是惰性的,这意味着如果您评估头部,则尾部可能保持“未评估”状态。
用 F# 术语来说,这实际上更接近seq 'a( IEnumerable<T>),它也是(可能)延迟计算的。
即便如此,F# 仍然带有一个内置的缺点列表-list类型。尽管它在 F# 中没有被延迟计算,但它仍然非常有用。
在许多方面,在 F# 中,list、array、 和seq是可以互换的,而且seq是奇怪的(因为它可以是惰性的和/或无限的)。
实际上,在 F# 中,list和array通常是可以互换的,因为它们具有相同的可供性。你能用 a 做什么list,你也可以用 an 做什么array,反之亦然。
然而,它们的用户体验和性能特征确实略有不同。F# 语言稍微偏爱列表而不是数组,因为如果您想在列表上创建或模式匹配,您可以使用语法[],而数组则要求您使用[||].
在某些算法中列表也可以更有效。许多函数算法通过递归构建列表。将元素添加到现有列表中是一种廉价的操作,因为您不必更改尾部。您只需更新列表指针以指向新的头。
另一方面,对于数组,每次想要追加一个元素时,都必须分配一个全新的数组并复制旧值。
这并不是说您不能有效地使用数组。你当然可以 - 特别是如果你可以预先计算数组的大小。
在 F# 中,有时数组很好,有时列表更好。就我个人而言,当我用 F# 编写代码时,我发现列表比数组或 s 更容易使用seq。