目前,梦想仍在继续,在我了解到的每个 haskell 概念中,我都更加着迷。然而,我还没有完全完成这个宝贵的@luqui 对我之前关于 catamorphism的问题的回答,我会回到它,直到它没问题。这是关于 Wikipedia 上的示例代码,处理BINARY trees 上的 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]
-- 最新的一行在“map g [y]”上并不讨好 ghc
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 = (+) }
-- 而这个最新的 sumTree 对于 ghc 也是错误的
我看到 > 和 +,就像 C++ 运算符 > 和 +。所以我不明白 ghc 在没有我给予它实现操作符 >/+ 的情况下对我生气。
其次,我必须承认我对 => (不同于 -> ???)和 @ 的感觉完全模糊,这似乎是模式匹配的指南。
您将如何更正此代码?
还有一个最新的问题,我也在尝试这样做,因为复合模式恰好是 C++ 中对我来说最重要的。很明显,我看到它几乎可以用 Haskell 中的一两行来描述(这对我来说真是太神奇了)。
但是你会如何表达这样一个事实:Leaf 和 Composite 的 Composition 构造函数可能具有某种相同的接口?(我知道这不是个好词,因为数据是不可变的,但我希望你能猜到——理解我的关注/目标)
这是总的编译错误;
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'
编辑 所以这是非二元变态的最终版本
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 似乎是类型类约束。
因此,设计模式 Composite 将通过在构造 Composition a 时应用类型类约束来实现。也许应该定义一个新的专业数据。但在这样做之前我应该学习类型类:-)