2013-10-22 93 views
4

缩写形式(这将解决我的问题的一个方法至少)如何查看类型是否是Haskell中的类的实例?

我怎样才能做这样的事情:

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 

这样,他们只需要实现方法来检索左,右,以及当前节点的值,prettyprint没有按” t需要了解内部结构。

然后我得到了到这里:

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的一个实例呢?或者还有什么其他方式可以解决这个问题?在面向对象的语言中,我可以很容易地检查一个类是否实现了一些东西,或者一个对象是否有方法。


,因为它不是一个需要showable树,我不能使用类似

prettyprint :: Show a => a -> String 

,这是一个需要showable树(按功能node返回)内的值。我也尝试将node改为Show b => a -> b而没有运气(还有一堆其他类型的class/preconditions /不管/我甚至不知道我在做什么)。

+0

,你可以让一切都显示的实例:'实例显示,其中显示_ =“”' – aavogt

回答

2

在你的班级中你有node :: a -> b其中a被固定为例示GenericBinaryTreeb是......真正的任何东西。完全没有任何限制,最终会得到一个根本无法使用的值,更不用说show

node :: Show b => a -> b方法提供了一种约束b必须Show能够后来你遇到了第二个问题:我们仍然不知道,具体是什么b是!

特别是,这就是为什么在class声明中使用不受约束的类型变量的好主意。你看他们在的地方,如

instance Alternative f where 
    empty :: f a 

表明,我们必须创建一个f容器,其内部具有零种元素的能力......所以还不如采取任何类型f a任何a任何责任。

一个解决办法可能是使用MultiParamTypeClasses

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-} 

class GenericBinaryTree b a | a -> b where 
    is_leaf :: a -> Bool 
    left :: a -> a 
    node :: a -> b 
    right :: a -> a 

showNode :: (Show b, GenericBinaryTree b a) => a -> String 
showNode = show . node 

编译就好了。

+0

呀看到我的最后一段我已经尝试过,不工作 – Raekye

+0

编辑来考虑下一个错误。 –

+0

有趣。那么我该如何定义实例?我尝试过'实例GenericBinaryTree(树a)a ...',它说“非法实例声明...”,我在两个文件中都包含了pragma。另外,是否有一种方法可以在没有MultiParamTypeClasses的情况下完成一般目标?是否有解决“简单形式”问题的方法(请参见问题的顶部) – Raekye

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] 

这里我们使用类型类中指定的方式树可以导航,这能解决您的问题,树可以有不同的结构。接下来的问题是如何显示节点值,这是通过在prettyprint_helper singnature中添加Show类型约束来解决的。 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 
+0

看起来不错,现在唯一的问题是我得到'''''prettyprint(Leaf)= GenericBinaryTree.prettyprint Leaf'因为'Leaf'构造函数没有任何东西来标识它的类型参数,所以''configuous type variable in constraint'...怎么可以我解决这个问题? – Raekye

+0

由于'Leaf'类型不需要显示,是否有添加某种“或者”约束的方法?既然它可能是一个Leaf,我们不需要显示它,否则它将成为一个分支,在这种情况下,第二个类型参数需要显示。 – Raekye

+0

@Raekye:你可以添加'prettyprint'的代码,以便你的评论更清晰吗? – Ankur

相关问题