非二叉树的变形与复合设计模式的初学者实现
目前,梦想仍在继续,对于我学到的每个 Haskell 概念,我都更加着迷。 然而,我还没有完全完成@luqui对我之前关于变形论的问题的回答,我会回来解决这个问题,直到一切正常为止。这是关于维基百科上的示例代码,处理二叉树上的变形。
尽管如此,我已经尝试对 NON BINARY 树实现变形,但我遇到了一些麻烦:
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 = (+) }
-- 并且这个最新的 sumTree 也是错误的ghc
我明白了>和 +,就像 C++ 运算符 >和+。所以我不明白 ghc 在我没有给它实现操作符 >/+ 或不实现的对象的情况下对我生气。
其次,我必须承认我对 => 的感觉完全模糊。 (与 -> ??? 不同)和 @ 似乎是模式匹配的指南。
您将如何更正此代码?
还有一个最新的问题, 我也在尝试这样做,因为复合模式恰好是 C++ 中对我来说最重要的。显然,我发现它几乎可以用 Haskell 中的一两行来描述(这对我来说真的很神奇)。
但是,haskell 的人会如何表达这样一个事实:Leaf 和 Composition 的 Composite 构造函数可能具有某种相同的 Interface? (我知道这不是一个好词,因为数据不可变,但我希望你能猜测并理解我的担忧/目标)
这是总的编译错误;
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 时应用类型类约束来实现。也许应该定义一个新的专门数据。但在这样做之前我应该学习类型类:-)
For the moment, the dream still goes on, at each haskell concept I learn I am more enticed.
Yet I havent completely fulfilled working on this precious @luqui's answer to my previous question about catamorphism, and i'm gonna come back at it until it's ok. It was about this sample code on Wikipedia, dealing with catamorphism on BINARY trees.
Nonetheless, I have tried implementing catamorphism for NON BINARY trees but I face some troubles:
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]
-- that latest line doesnt please ghc upon "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 = (+) }
-- and this lattest sumTree is wrong too for ghc
I see > and +, just like the C++ operators > and +. So I don't understand ghc is angry at me without my giving to it objets implementing opertor >/+ or not.
Secondly I must admit I'm completely hazy about the sense of => (different from -> ???) and @ which seems to be like a guide for pattern matching.
How would you correct this code ?
And a latest question,
I am also trying doing this because the Composite Pattern happened to be the most important for me in C++. And obviously I see it can be almost described in only one/two line in Haskell (that is truely amazing for me).
But how would you haskell people express the fact that Leaf and Composite constructor of Composition may have some kind of the same Interface? (I know it's not the good word since data are not mutable, but I hope you can guess-understand my concern/goal)
this is the total compilation error;
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'
EDIT
So this is the final version for non binary 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 }
And according to the valid answer below: what I was asking for haskell equivalent of C++ Interfaces contracts seems to be typeclasses constraints.
So the design pattern Composite would be achieved by applying typeclass constraints when constructing the Composition a. Maybe a new specialized data should be define. But I should learn typeclasses before doing that :-)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这里有一些不同的错误,所以我不确定处理它的最佳方法,但到底是什么。
将来,尝试包含更多 GHC 提供的错误。
在:
函数
foldCompose
有两个错误,我可以看到,只有其中之一会被类型检查器捕获。您正在对
(Composite [y])
进行模式匹配,该模式仅匹配一个元素的列表。您可能需要(Composite ys)
,它将ys
绑定到整个列表。map g [y]
不会通过类型检查器,因为您已经将g
定义为采用r
列表,但你给它一个a
列表。为了将
a
转换为r
,您需要对其应用CompositionAlgebra
:g (map (foldComposition a) ys)
所以我会把它写成:
对于你的下一个错误:
在 Haskell 中,一个类型变量(比如这里的
a
)完全可以通过它的孤独来填充任何类型呼叫者,由呼叫者选择。这意味着在您的类型签名中,您声明函数
maxPair
适用于每种输入类型。 GHC(以自己的方式)抱怨运算符>
不适用于每种类型,因此拒绝编译您的程序。您需要使用类型类来解决这个问题。在 Haskell 中,类型类允许调用者选择要使用的类型,但有一些限制。我建议阅读 Haskell 类型类教程。
正确的类型签名是:
将
Ord
约束应用于类型a
。另外,您应该使用标准函数
max
。There are a few different errors here, so I'm not sure the best way to deal with it on SO, but what the heck.
In the future, try to include more of the errors that GHC provides.
In:
The function
foldCompose
has two errors that I can see, only one of which will be caught by the type checker.You're pattern matching on
(Composite [y])
, which will only match for lists of one element. You likely want(Composite ys)
, which bindsys
to the entire list.map g [y]
won't pass the type checker, because you've already definedg
as taking a list ofr
, but you're giving it a list ofa
.In order to convert an
a
to anr
you need to apply yourCompositionAlgebra
to it:g (map (foldComposition a) ys)
So I would write this as:
For your next error:
In Haskell, a type variable (like
a
here) all by its lonesome may be filled in with any type at all by the caller, at the caller's choosing.This means in your type signature you're claiming that the function
maxPair
will work for every input type. GHC complains (in its own way) that the operator>
doesn't work for every type, and therefor refuses to compile your program.You'll need to use typeclasses to solve this problem. In Haskell, typeclasses let the caller pick the types to use, but with some constraints. I recommend reading a Haskell tutorial on typeclasses.
The correct type signature would be:
Which applies the
Ord
constraint to the typea
.Also, you should be using the standard function
max
.考虑 elem 函数,它测试列表是否包含某个值。您可以将其定义为
哪个签名有此功能?看起来像
elem :: a -> [一]->布尔。但是编译器会抱怨,因为你写了
位于 Eq 类型类。因此,您需要指定类似“对于 Eq 中的所有 a ...”之类的内容。为此,您需要x == y
,并且不是为每个a
定义了==
函数,只为那些 < code>a=>
。因此elem
的正确签名是elem :: Eq a =>一个-> [一]->布尔。
@
使您可以为整个结构命名并同时对其进行模式匹配。例如,如果您有模式a@(x:xs)
并且使用[1,2,3,4]
调用该函数,则a 是
[1,2,3,4]
,x
是1
,xs
是[2,3,4]
。Consinder the elem function, which tests if a list contains a certain value. You could define it as
Which signature has this function? Looks like
elem :: a -> [a] -> Bool
. But the compiler will complain because you wrotex == y
, and not for everya
the==
function is defined, only for thosea
which are in the Eq type class. So you need to specify something like "For all a which are in Eq...". And exactly for this you need=>
. So the correct signature forelem
iselem :: Eq a => a -> [a] -> Bool
.The
@
gives you the possibility to give a whole structure a name and to pattern match on it at the same time. E.g. if you have the patterna@(x:xs)
and you call that function with[1,2,3,4]
, thena
is[1,2,3,4]
,x
is1
andxs
is[2,3,4]
.