Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell中的亚同态与树遍历_Haskell_Tree Traversal_Catamorphism - Fatal编程技术网

Haskell中的亚同态与树遍历

Haskell中的亚同态与树遍历,haskell,tree-traversal,catamorphism,Haskell,Tree Traversal,Catamorphism,我不耐烦了,期待着理解变形:) 我只练习了真实世界Haskell教程的开头部分。所以,也许我现在要求的太多了,如果是这样的话,就告诉我应该学习的概念 下面,我引述 我想知道你对下面的foldTree的看法,这是一种遍历树的方法,与其他的问答相比,也是关于遍历树的。(独立于是否为二进制,我认为可以编写下面的反同构,以便管理n元树) 我把我理解的东西写进评论,如果你能纠正我,澄清一些事情,我会很高兴 {-this is a binary tree definition-} data Tree a =

我不耐烦了,期待着理解变形:)

我只练习了真实世界Haskell教程的开头部分。所以,也许我现在要求的太多了,如果是这样的话,就告诉我应该学习的概念

下面,我引述

我想知道你对下面的foldTree的看法,这是一种遍历树的方法,与其他的问答相比,也是关于遍历树的。(独立于是否为二进制,我认为可以编写下面的反同构,以便管理n元树)

我把我理解的东西写进评论,如果你能纠正我,澄清一些事情,我会很高兴

{-this is a binary tree definition-}
data Tree a = Leaf a
            | Branch (Tree a) (Tree a)

{-I dont understand the structure between{} 
however it defines two morphisms, leaf and branch 
leaf take an a and returns an r, branch takes two r and returns an r-} 
data TreeAlgebra a r = TreeAlgebra { leaf   :: a      -> r
                                   , branch :: r -> r -> r }

{- foldTree is a morphism that takes: a TreeAlgebra for Tree a with result r, a Tree a
and returns an r -} 
foldTree :: TreeAlgebra a r -> Tree a -> r
foldTree a@(TreeAlgebra {leaf   = f}) (Leaf   x  ) = f x
foldTree a@(TreeAlgebra {branch = g}) (Branch l r) = g (foldTree a l) (foldTree a r)
在这一点上,我有很多困难,我似乎猜测,态射叶 将应用于任何叶子 但为了真正使用这段代码,foldTree需要一个定义好的TreeAlgebra, 一种树形文胸,它有一个定义的态射叶以便做某事?
但是在这种情况下,在foldTree代码中,我期望{f=leaf},而不是相反


非常欢迎您的任何澄清。

不太清楚您在问什么。但是,是的,您将一个
TreeAlgebra
馈送到
foldTree
中,该树对应于您要在树上执行的计算。例如,要对
Int
s树中的所有元素求和,可以使用以下代数:

sumAlgebra :: TreeAlgebra Int Int
sumAlgebra = TreeAlgebra { leaf = id
                         , branch = (+) }
这意味着,要获取叶的总和,请对叶中的值应用
id
(不执行任何操作)。要得到分支的和,将每个子级的和相加

对于分支,我们可以说
(+)
,而不是说
\x y->sumTree x+sumTree y
,这是亚同态的本质属性。它说,要计算某个递归数据结构上的某个函数
f
,其直接子函数的
f
值就足够了

Haskell是一种非常独特的语言,因为我们可以抽象地形式化退化的概念。让我们为树中的单个节点创建一个数据类型,通过其子节点进行参数化:

data TreeNode a child
    = Leaf a
    | Branch child child
看到我们在那里做了什么吗?我们只是用我们选择的类型替换了递归子对象。这样我们可以在折叠时把子树的和放在那里

现在来看看真正神奇的事情。我将用pseudohaskell来写这篇文章——用真实的Haskell来写是可能的,但是我们必须添加一些注释来帮助类型检查器,这可能会有点混乱。我们采用参数化数据类型的“固定点”——也就是说,构造一个数据类型
T
,使得
T=TreeNode a T
。他们称这个操作符为
Mu

type Mu f = f (Mu f)
仔细看这里。
Mu
的参数不是一种类型,如
Int
Foo->Bar
。它是一个类型构造函数,如
可能
TreeNode Int
——Mu的参数本身带有一个参数。(抽象类型构造函数的可能性是使Haskell的类型系统在其表达能力方面真正脱颖而出的原因之一)

因此类型
muf
被定义为取
f
并用
muf
本身填充其类型参数。我将定义一个同义词来减少一些噪音:

type IntNode = TreeNode Int
扩展
Mu IntNode
,我们得到:

Mu IntNode = IntNode (Mu IntNode)
           = Leaf Int | Branch (Mu IntNode) (Mu IntNode)
您是否看到
Mu IntNode
如何等效于您的
树Int
?我们刚刚将递归结构拆开,然后使用
Mu
将其重新组合起来。这给了我们一个优势,我们可以同时讨论所有
Mu
类型。这就给了我们定义一个亚同态所需要的东西

让我们定义一下:

type IntTree = Mu IntNode
我说过,反同构的基本性质是,为了计算某个函数
f
,它的直接子函数的
f
值就足够了。让我们调用我们试图计算的对象的类型
r
,数据结构
node
IntNode
可能是这个的一个实例)。因此,要在特定节点上计算
r
,我们需要将节点及其子节点替换为它们的
r
s。此计算具有类型
节点r->r
。因此,一个反同构表示,如果我们有其中一个计算,那么我们可以计算整个递归结构的
r
(记住递归在这里用
Mu
明确表示):

为我们的示例制作此混凝土,如下所示:

cata :: (IntNode r -> r) -> IntTree -> r
重新启动时,如果我们可以将具有
r
s的节点作为其子节点并计算
r
,那么我们可以为整个树计算
r

为了实际计算它,我们需要
节点
成为
函子
——也就是说,我们需要能够将任意函数映射到节点的子节点上

fmap :: (a -> b) -> node a -> node b
对于
IntNode
,这可以直接完成

fmap f (Leaf x) = Leaf x                  -- has no children, so stays the same
fmap f (Branch l r) = Branch (f l) (f r)  -- apply function to each child
现在,最后,我们可以给出
cata
的定义(
函子节点
约束只是说
节点
有一个合适的
fmap
):

我使用参数名
t
作为“tree”的助记符值。这是一个抽象、密集的定义,但实际上非常简单。它说:递归地对
t
的每个子节点(它们本身就是
Mu节点
s)执行
cata f
——我们在树上进行的计算,以获得
节点r
,然后将该结果传递给
f
计算
t
本身的结果

从一开始,您定义的代数本质上是定义
节点r->r
函数的一种方法。实际上,给定一个
TreeAlgebra
,我们可以很容易地得到fold函数:

foldFunction :: TreeAlgebra a r -> (TreeNode a r -> r)
foldFunction alg (Leaf a) = leaf alg a
foldFunction alg (Branch l r) = branch alg l r
因此,可以根据我们的泛型定义树的亚同态,如下所示:

type Tree a = Mu (TreeNode a)

treeCata :: TreeAlgebra a r -> (Tree a -> r)
treeCata alg = cata (foldFunction alg)
我没时间了。我知道这很快就变得抽象了,但我跳了
foldFunction :: TreeAlgebra a r -> (TreeNode a r -> r)
foldFunction alg (Leaf a) = leaf alg a
foldFunction alg (Branch l r) = branch alg l r
type Tree a = Mu (TreeNode a)

treeCata :: TreeAlgebra a r -> (Tree a -> r)
treeCata alg = cata (foldFunction alg)