初始实现非二叉树的Catamorphism与复合设计模式

时间:2011-01-20 00:33:57

标签: design-patterns haskell composite catamorphism

目前,梦想还在继续,每个哈克尔概念我都知道我更有吸引力。 然而,我还没有完全完成这个珍贵的@ luqui对my previous question about catamorphism的回答,我会回来直到它没问题。这是关于维基百科上的这个示例代码,处理catamorphism on BINARY trees

尽管如此,我尝试为 NON BINARY 树实施catamorphism,但我遇到了一些麻烦:

data Composition a = Leaf a
                   | Composite [Composition a]

data CompositionAlgebra a r = CompositionAlgebra { leaf      :: a →  r
                                                 , composite :: [r] →  r }

foldComposition :: CompositionAlgebra a r →  Composition a →  r
foldComposition a@(CompositionAlgebra {leaf   = f}) (Leaf   x  ) = f x
foldComposition a@(CompositionAlgebra {composite = g}) (Composite [y]) =  map g [y] 

- 最新的一行并没有取悦ghc“map g [y]”

maxOfPair :: a →  a →  a
maxOfPair x y = if( x > y) -- this doesnt please ghc either, Ordering trouble
                then (x) 
                else (y)

maxInList :: [a] →  a
maxInList (x:xs) = maxOfPair x (maxInList xs)

treeDepth :: CompositionAlgebra a Integer
treeDepth = CompositionAlgebra { leaf = const 1, composite = λx →  1 + maxInList x }

sumTree :: (Num a) ⇒ CompositionAlgebra a a
sumTree = CompositionAlgebra { leaf = id, composite = (+) } 

- 对于ghc来说,这个最直接的sumTree也是错误的

我看到>和+,就像C ++运算符>和+。所以我不明白ghc对我很生气,如果没有我给它实现opertor> / +或者不执行它。

其次我必须承认我对=>的感觉完全朦胧(不同于 - > ???)和@似乎就像模式匹配的指南。

您如何更正此代码?

最新的问题, 我也在尝试这样做,因为复合模式恰好是我在C ++中最重要的。显然我看到它几乎可以在Haskell的一两行中描述(这对我来说真是太棒了。)

但是你怎么会有人表达这样一个事实,即Composition和Composite的构造函数可能有某种相同的接口? (我知道这不是好词,因为数据不可变,但我希望你能猜到 - 理解我的关注/目标)

这是总编译错误;

src\Main.hs:27:79:
    Couldn't match expected type `[r]'
           against inferred type `Composition a'
    In the expression: y
    In the second argument of `map', namely `[y]'
    In the expression: map g [y]

src\Main.hs:30:20:
    Could not deduce (Ord a) from the context ()
      arising from a use of `>' at src\Main.hs:30:20-24
    Possible fix:
      add (Ord a) to the context of the type signature for `maxOfPair'
    In the expression: (x > y)
    In the expression: if (x > y) then (x) else (y)
    In the definition of `maxOfPair':
        maxOfPair x y = if (x > y) then (x) else (y)

src\Main.hs:41:0:
    Occurs check: cannot construct the infinite type: a = [a] -> [a]
    When generalising the type(s) for `sumTree'

修改 所以这是非二元catamorphism的最终版本

data Composant a = Leaf a
                 | Composite [Composant a]

data CompositionAlgebra a r = CompositionAlgebra { leaf      :: a →  r
                                             , composite :: [r] →  r }

foldComposition :: CompositionAlgebra a r →  Composant a →  r
foldComposition a@(CompositionAlgebra {leaf = f}) (Leaf x) = f x
foldComposition a@(CompositionAlgebra {composite = g}) (Composite ys) =  g(map(foldComposition a) ys)

maxOfPair :: Ord a ⇒ a →  a →  a
maxOfPair x y = if( x > y) 
                then (x) 
                else (y)

maxInList :: Ord a => [a] →  a
maxInList (x:xs) = maxOfPair x (maxInList xs)

treeDepth :: CompositionAlgebra a Integer
treeDepth = CompositionAlgebra { leaf = const 1, composite = λx →  1 + maxInList x }

addList :: Num a ⇒ [a] → a
addList (x:xs) = x + addList xs 

sumTree :: (Num a) ⇒ CompositionAlgebra a a
sumTree = CompositionAlgebra { leaf = id, composite = addList } 

根据下面的有效答案:我要求的等同于C ++接口契约的haskell似乎是类型约束。

因此,在构造合成a时,应用类型类约束可以实现设计模式Composite。也许应该定义一个新的专业数据。但在这之前我应该​​学习类型类: - )

2 个答案:

答案 0 :(得分:5)

这里有一些不同的错误,所以我不确定在SO上处理它的最佳方法,但是到底是什么。

将来,请尝试包含更多GHC提供的错误。

在:

foldComposition :: CompositionAlgebra a r →  Composition a →  r
foldComposition a@(CompositionAlgebra {leaf   = f}) (Leaf   x  ) = f x
foldComposition a@(CompositionAlgebra {composite = g}) (Composite [y]) =  map g [y]

函数foldCompose有两个我可以看到的错误,其中只有一个会被类型检查器捕获。

  1. 您在(Composite [y])上进行模式匹配,只匹配一个元素的列表。您可能希望(Composite ys)ys绑定到整个列表。

  2. map g [y]不会传递类型检查器,因为您已经将g定义为列出r,但是您要给它一个列表a

    要将a转换为r,您需要将CompositionAlgebra应用于g (map (foldComposition a) ys)

  3. 所以我会把它写成:

    foldComposition :: CompositionAlgebra a r →  Composition a →  r
    foldComposition a@(CompositionAlgebra {leaf   = f}) (Leaf   x  ) = f x
    foldComposition a@(CompositionAlgebra {composite = g}) (Composite ys) = g (map (foldComposition a) ys)
    

    您的下一个错误:

    maxOfPair :: a →  a →  a
    maxOfPair x y = if( x > y) -- this doesnt please ghc either, Ordering trouble
                    then (x) 
                    else (y)
    

    在Haskell中,一个类型变量(如a这里)所有的寂寞都可以由调用者根据调用者的选择用任何类型填充。

    这意味着在您的类型签名中,您声称函数maxPair适用于每个输入类型。 GHC(以自己的方式)抱怨运算符>不适用于每个类型,因此拒绝编译您的程序。

    您需要使用类型类来解决此问题。在Haskell中,类型类允许调用者选择要使用的类型,但是有一些约束。我建议你阅读Haskell tutorial on typeclasses

    正确的类型签名是:

    maxOfPair :: Ord a => a →  a →  a
    

    Ord约束应用于类型a

    此外,您应该使用标准函数max

答案 1 :(得分:3)

  

其次,我必须承认我完全   朦胧的感觉=> (不同   来自 - > ???)和@似乎是   像模式匹配指南。

构造elem函数,该函数测试列表是否包含特定值。您可以将其定义为

elem _ [] = False
elem x (y:ys) | x == y = True
              | otherwise = elem x ys

哪个签名有此功能?看起来像elem :: a -> [a] -> Bool。但编译器会抱怨,因为您编写了x == y,而不是每个a ==函数都定义了,仅适用于Eq type class中的a 。因此,您需要指定类似“对于所有在Eq中的所有...”的内容。确切地说,你需要=>。因此elem的正确签名是elem :: Eq a => a -> [a] -> Bool

@使您可以为整个结构提供名称并同时对其进行模式匹配。例如。如果您使用模式a@(x:xs)并使用[1,2,3,4]调用该函数,则a[1,2,3,4]x1且{{1是} xs