简短形式(这至少可以解决我的问题)
我该怎么做:
try_to_show :: a -> String
try_to_show val = if (val is instance of Show) (show val) else "Cannot show"
我可能完全错了(unhaskell方式);我刚刚学习,请告诉我是否有更好的方法来解决这个问题。
背景信息:我正在编写一堆树结构。我想重用我的prettyprint
函数用于二叉树。并非所有树都可以使用通用Node
/ Branch
数据类型;不同的树需要不同的额外数据。因此,要重用prettyprint
函数,我想创建一个类,不同的树将是以下实例:
class GenericBinaryTree a where
is_leaf :: a -> Bool
left :: a -> a
node :: a -> b
right :: a -> a
这样他们只需要实现检索left,right和current节点值的方法,而prettyprint不需要知道内部结构。
然后我到了这里:
prettyprint_helper :: GenericBinaryTree a => a -> [String]
prettyprint_helper tree
| is_leaf tree = []
| otherwise = ("{" ++ (show (node tree)) ++ "}") : (prettyprint_subtree (left tree) (right tree))
where
prettyprint_subtree left right =
((pad "+- " "| ") (prettyprint_helper right)) ++ ((pad "`- " " ") (prettyprint_helper left))
pad first rest = zipWith (++) (first : repeat rest)
我收到Ambiguous type variable 'a0' in the constraint: (Show a0) arising from a use of 'show'
(show (node tree))
错误
这是最基本的树数据类型和实例定义的示例(我的其他树有其他字段,但它们与通用prettyprint
函数无关)
data Tree a
= Branch (Tree a) a (Tree a)
| Leaf
instance GenericBinaryTree (Tree a) where
is_leaf Leaf = True
is_leaf _ = False
left (Branch left node right) = left
right (Branch left node right) = right
node (Branch left node right) = node
我可以定义node :: a -> [String]
并在每个实例/树的类型中处理字符串化,但这感觉更整洁。就prettyprint
而言,我只需要一个字符串表示,但如果我稍后添加其他通用二叉树函数,我可能需要实际值。
那么,如果节点值是Show
的实例,我怎么能写这个呢?或者我应该采取其他什么方式来解决这个问题?在面向对象的语言中,我可以轻松地检查一个类是否实现了某个东西,或者一个对象是否有一个方法。
我不能使用像
这样的东西prettyprint :: Show a => a -> String
因为它不是需要显示的树,所以树内的值(由函数node
返回)需要显示。我还尝试将node
更改为Show b => a -> b
,但没有运气(还有一些其他类型/先决条件/不管/我甚至不知道我在做什么)。
答案 0 :(得分:4)
您无法执行问题中提到的第一个解决方案。你可以做的是尝试类似的东西:
class GenericBinaryTree t where
is_leaf :: t a -> Bool
left :: t a -> t a
node :: t a -> a
right :: t a -> t a
prettyprint_helper :: (GenericBinaryTree f, Show a) => f a -> [String]
这里我们使用类型类来指定树可以导航的方式,这解决了树可以具有不同结构的问题。下一个问题是如何显示节点值,这是通过在Show
singnature中添加prettyprint_helper
类型类约束来解决的。 GenericBinaryTree
实例实现:
instance GenericBinaryTree Tree where
is_leaf Leaf = True
is_leaf _ = False
left (Branch left node right) = left
right (Branch left node right) = right
node (Branch left node right) = node
答案 1 :(得分:2)
在您的课程中,您node :: a -> b
已修复a
以实例化GenericBinaryTree
,但b
确实是......在没有任何限制的情况下,您最终会得到一个根本无法使用的值,更不用说show
。
node :: Show b => a -> b
方法提供了b
必须Show
能够的约束,但是您遇到了第二个问题:我们仍然不知道具体是什么{{1}是的!
特别是,这就是为什么在b
声明中包含无约束类型变量的好主意。你可以在像
class
建议我们能够创建一个instance Alternative f where
empty :: f a
容器,其中包含零元素...因此,对于任何f
,任何类型的f a
都可以。
解决方案可能是使用MultiParamTypeClasses
a
编译得很好。