首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无标记树的“`unfold`”的正确定义是什么?

无标记树的“`unfold`”的正确定义是什么?
EN

Stack Overflow用户
提问于 2015-02-21 23:06:51
回答 1查看 561关注 0票数 9

我一直在考虑如何为以下类型实现等效的unfold

代码语言:javascript
复制
data Tree a = Node (Tree a) (Tree a) | Leaf a | Nil

这并不明显,因为列表的标准unfold返回一个值和下一个种子。对于这种数据类型,这是没有意义的,因为在到达叶节点之前没有“值”。这样,返回新种子或以价值停止才是真正有意义的。我使用的定义是:

代码语言:javascript
复制
data Drive s a = Stop | Unit a | Branch s s deriving Show

unfold :: (t -> Drive t a) -> t -> Tree a
unfold fn x = case fn x of
    Branch a b -> Node (unfold fn a) (unfold fn b)
    Unit a     -> Leaf a
    Stop       -> Nil

main = print $ unfold go 5 where
    go 0 = Stop
    go 1 = Unit 1
    go n = Branch (n - 1) (n - 2)

虽然这似乎有效,但我不确定这是否应该是这样的。所以,这就是问题所在:正确的方法是什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-02-22 00:16:19

如果您认为数据类型是函子的不动点,那么您可以看到您的定义是对列表大小写的合理概括。

代码语言:javascript
复制
module Unfold where

在这里,我们从定义函子f的不动点开始:它是一个f层,后面是一些更多的不动点:

代码语言:javascript
复制
newtype Fix f = InFix { outFix :: f (Fix f) }

为了使事情稍微清楚一些,下面是对应于列表和树的函子的定义。它们的形状与数据类型基本相同,只不过我们有一个额外的参数来替换递归调用。换句话说,它们描述了列表/树的一个层是什么样子的,并且在可能的子结构r上是通用的。

代码语言:javascript
复制
data ListF a r = LNil | LCons a r
data TreeF a r = TNil | TLeaf a | TBranch r r

列表和树分别是ListF和TreeF的不动点:

代码语言:javascript
复制
type List a = Fix (ListF a)
type Tree a = Fix (TreeF a)

无论如何,您现在对这个不动点业务有了更好的直觉,我们可以看到有一种为这些业务定义unfold函数的通用方法。

给定原始种子以及接受种子并构建一个递归结构为新种子的f层的函数,我们可以构建一个完整的结构:

代码语言:javascript
复制
unfoldFix :: Functor f => (s -> f s) -> s -> Fix f
unfoldFix node = go
  where go = InFix . fmap go . node

这个定义专门针对通常的列表中的unfold或树的定义。换句话说:你的定义确实是正确的。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28652452

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档