是我!
我认为最好的方法可能是通过一个例子来工作。让我们走吧……
Deep (Two 1 2) (Two 7 8))
(Deep (One (Node2 3 4)) (One (Node2 5 6))
Empty
这是一个序列,有些简化(例如,省略了 Elem 包装器)。
让我们对此进行初始化;尾巴本质上是对称的。我们的递归算法将省略空的 init,只包含非空的东西。
前缀
因此,init 的前缀数字本质上将使用fmap digitToTree (initsDigit (Two 1 2)) 生成。
initsDigit (Two 1 2) = Two (One 1) (Two 1 2)
fmap digitToTree (Two (One 1) (Two 1 2)) =
Two (Single 1) (Deep (One 1) Empty (One 2))
所以这是整个事情的前两个初始值,这个数字将是inits 结果的前缀数字。 (除了我们要在完成后添加空序列,但我们现在先忽略它。)
内层树
现在让我们看一下内部树的初始化,将其视为FingerTree (Node a)——我们还不打算拆开节点,它只是一个包含两个节点的两个元素FingerTree。这个细节我就不说了,只是通过相同的算法递归,我只是要神奇的得到结果
Deep
(One (Single (Node2 3 4)))
Empty
(One (Deep (One (Node2 3 4)) Empty (One (Node2 5 6))))
:: FingerTree (FingerTree (Node a))
所以这些是内部树的初始值。这些如何对应于外部树的初始值?内层树的每个init对应一棵包含
的树
- 原始树的前缀数字,
Two 1 2
- 除了内部树的 init 的最后一个
Node 之外的所有内容
- 内部树的 init 的最后一个
Node 的一些前缀
因此,通过获取内部树的 init 获得的每个 FingerTree (Node a) 将映射到 Node (FingerTree a),其中包含 FingerTree 用于 FingerTree (Node a) 中最后一个节点的每个 init。
因此例如Single (Node2 3 4),在其最后一个节点被提取后,将被分解为Empty和Node2 3 4,得到的Node (FingerTree a)是
Node2
(Deep (Two 1 2 {- prefix of original tree -})
Empty
(One 3 {- first prefix of Node2 3 4 -}))
(Deep (Two 1 2)
Empty
(Two 3 4 {- second prefix of Node2 3 4 -}))
对于内部树的另一个前缀 Deep (One (Node2 3 4)) Empty (One (Node2 5 6)),提取最后一个 Node 得到余数 Single (Node2 3 4) 和提取的节点 Node2 5 6,因此得到 Node (FingerTree a):
Node2
(Deep (Two 1 2 {- prefix of original tree -})
(Single (Node2 3 4) {- init of the inner tree minus the last Node -})
(One 5 {- first prefix of Node2 5 6 -})
(Deep (Two 1 2 {- prefix of original tree -})
(Single (Node2 3 4) {- init of the inner tree minus the last Node -})
(Two 5 6 {- second prefix of Node2 5 6 -}))
所以这是一个将FingerTree (Node a)(内部树的单个初始化)带到Node (FingerTree a) 的操作。因此,通过递归获取内部树的初始值作为FingerTree (FingerTree (Node a)),我们将这个函数映射到它们上以获得FingerTree (Node (FingerTree a)),这正是我们想要的;它是整个事物的 inits 的内部树。
后缀
最后,有原树的inits组成
这些成为init树的后缀数字。 initsDigit (Two 7 8) 返回Two (One 7) (Two 7 8),我们基本上只是将\sf -> Deep pr m sf 映射到它上面,得到
Two
(Deep (Two 1 2 {- original -})
(Deep (One (Node2 3 4)) Empty (One (Node2 5 6)) {- original -})
(One 7 {- first init of original suffix digit -}))
(Deep (Two 1 2 {- original -})
(Deep (One (Node2 3 4)) Empty (One (Node2 5 6)) {- original -})
(Two 7 8 {- second init of original suffix digit -}))
所以,这并不是代码的组织方式。我们已经描述了从FingerTree a 到FingerTree (FingerTree a) 的函数,但实际的实现基本上是加上fmap,因为我们最终总是需要以某种方式映射元素——即使它只是包装新类型。但这基本上就是我们正在做的事情。