如何查看类型是否是Haskell中类的实例?

时间:2013-10-22 03:34:16

标签: 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

这样他们只需要实现检索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,但没有运气(还有一些其他类型/先决条件/不管/我甚至不知道我在做什么)。

2 个答案:

答案 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

编译得很好。