Jared Tobin is one of our consultants at fugue.co—he’s a programmer and researcher based out of Auckland, New Zealand. Jared’s article in this month’s issue of PragPub, The Pragmatic Bookshelf’s magazine affiliation, is a helpful read if you’re interested in functional programming and Haskell in particular. Check out “Practical Recursion Schemes” here.
贾里德·托宾(Jared Tobin)是fugue.co的顾问之一,他是一名来自新西兰奥克兰的程序员和研究员。 如果您对函数式编程特别是Haskell感兴趣,那么Jared在本月的PragPub杂志(实用书架的杂志隶属关系)上的文章对您很有帮助。 在此处查看“实用递归方案”。
Recursion schemes are simple, composable combinators that automate traversing nested data structures. They are a powerful abstraction that can be implemented in any language with first-class functions. Jared explores various schemes and their applications using Haskell, but the lessons here can be applied in Clojure or any true functional language.
递归方案是简单的,可组合的组合器,可自动遍历嵌套的数据结构。 它们是强大的抽象,可以用任何具有一流功能的语言来实现。 Jared使用Haskell探索了各种方案及其应用,但是这里的课程可以用Clojure或任何真正的函数式语言来应用。
The article details a number of recursion scheme examples. One of them is a particularly concise implementation of mergesort and, to wet your whistle for the kind of code you can write using recursion schemes, Jared elaborates on that example below.
本文详细介绍了许多递归方案示例。 其中之一是mergesort的一种特别简洁的实现,并且为了让您为使用递归方案可以编写的那种代码而烦恼,Jared在下面的示例中进行了详细说明。
按样式排序 (Sorting with Style)
Mergesort is a famous comparison-based sorting algorithm that starts by first recursively dividing a collection of orderable elements into smaller subcollections, and then finishes by recursively sorting and merging the smaller subcollections together to reconstruct the original (but now sorted) one.
Mergesort是一种著名的基于比较的排序算法,首先将可排序元素的集合递归地划分为较小的子集合,然后以递归的方式将较小的子集合归并并合并在一起以重建原始(但现在已排序)集合。
A clear implementation of mergesort should by definition be as faithful to that high-level description as possible. We can get pretty close to that using this whole recursion schemes business.
根据定义,对mergesort的清晰实现应尽可能忠实于该高级描述。 我们可以使用整个递归方案业务与之非常接近。
Start with a collection of orderable elements. We can subdivide the collection into a bunch of smaller collections by using a binary tree:
从可订购元素的集合开始。 我们可以使用二叉树将集合细分为一堆较小的集合:
data TreeF a r =
EmptyF
| LeafF a
| NodeF r r
deriving Functor
data TreeF a r =
EmptyF
| LeafF a
| NodeF r r
deriving Functor
The idea is that each node in the tree holds two subtrees, each of which contains half of the remaining elements. We can build a tree like this from a collection—say, a basic Haskell list. The following unfolder
function defines what part of a tree to build for any corresponding part of a list:
这个想法是树中的每个节点都包含两个子树,每个子树包含剩余元素的一半。 我们可以从集合中构建像这样的树-例如基本的Haskell列表。 以下unfolder
功能定义了列表的任何对应部分要构建的树的哪一部分:
On the other hand, we can collapse an existing tree back into a list. The following folder
function defines how to collapse any given part of a tree into the corresponding part of a list:
另一方面,我们可以将现有树折叠回到列表中。 以下folder
函数定义如何将树的任何给定部分折叠到列表的相应部分中:
folder EmptyF = [] folder (LeafF x) = [x] folder (NodeF l r) = merge l r
folder EmptyF = [] folder (LeafF x) = [x] folder (NodeF l r) = merge l r
Now to sort a list we can just glue these instructions together using what’s called a hylomorphism.
现在要对列表进行排序,我们可以使用所谓的同形将这些指令粘合在一起。
And it works just like you’d expect:
它的工作原理与您期望的一样:
> mergesort [1,10,3,4,5]
[1,3,4,5,10]
> mergesort "aloha"
"aahlo"
> mergesort [True, False, False, True, False]
[False, False, False, True, True]
> mergesort [ 1 , 10 , 3 , 4 , 5 ]
[ 1 , 3 , 4 , 5 , 10 ]
> mergesort "aloha"
"aahlo"
> mergesort [T rue , F alse , F alse , T rue , F alse ]
[F alse , F alse , F alse , T rue , T rue ]
Pretty concise! The code is eminently clean and faithful to the high-level algorithm description: first, recursively divide a collection into smaller subcollections—via a binary tree and unfolder
—and then recursively sort and merge the subcollections to reconstruct the (now sorted) original one—via folder
.
简明扼要! 该代码非常干净,并且忠实于高级算法描述:首先,通过二叉树和unfolder
将一个集合递归地划分为较小的子集合,然后递归地对子集合进行排序和合并,以重建(现在已排序的)原始集合。通过folder
。
翻译自: https://www.pybloggers.com/2015/12/practical-recursion-schemes-at-pragpub/