2011-04-22 81 views
14

请参阅下面的代码示例。它不会编译。我曾想过也许是因为它必须为测试函数中的第一个参数设置一个类型。但这是没有道理的,因为如果我没有模式匹配,所以它会编译,我可以称它为MyObj11 5MyObj21 5这是两种不同的类型。您可以在类型约束参数上设置匹配构造函数吗?

那么这是什么限制,所以你不能在类型约束参数的构造函数上模式匹配?还是有一些你可以的机制?

class SomeClass a where toString :: a -> String 

instance SomeClass MyType1 where toString v = "MyType1" 
instance SomeClass MyType2 where toString v = "MyType2" 

data MyType1 = MyObj11 Int | MyObj12 Int Int 
data MyType2 = MyObj21 Int | MyObj22 Int Int 

test :: SomeClass a => a -> String 
test (MyObj11 x) = "11" 
test (MyObj12 x y) = "12" -- Error here if remove 3rd line: rigid type bound error 
test (MyObj22 x y) = "22" -- Error here about not match MyType1. 
+0

如果haskell的类是可关闭的 - 也就是说,您可以为每个实现指定行为,这可能是有意义的。但是Haskell类是开放的 - 当'instance SomeClass SomeoneElsesType whereString v =“mwahahahah”''时,如果给定'SomeoneElsesType'类型的值,'test'应该做些什么?答案是处理这个问题的正确方法。 – rampion 2011-04-22 21:43:20

+3

这个问题对我来说似乎很明显:它会做任何模式匹配说它应该。如果没有模式匹配,就会像其他任何这样的情况一样出现这样的错误。我没有看到区别。 – mentics 2011-04-22 22:44:37

回答

19

它是什么,一个类型的类约束参数限制在构造函数,所以你不能模式匹配?

当您在显式构造函数上进行模式匹配时,您将提交给特定的数据类型表示。这种数据类型不是在类的所有实例之间共享的,所以不可能用这种方式编写适用于所有实例的函数。

相反,你需要不同的行为,你想与每个实例相关联,就像这样:现在

class C a where 
    toString :: a -> String 
    draw  :: a -> String 

instance C MyType1 where 
    toString v = "MyType1" 

    draw (MyObj11 x) = "11" 
    draw (MyObj12 x y) = "12" 

instance C MyType2 where 
    toString v = "MyType2" 

    draw (MyObj22 x y) = "22" 

data MyType1 = MyObj11 Int | MyObj12 Int Int 
data MyType2 = MyObj21 Int | MyObj22 Int Int 

test :: C a => a -> String 
test x = draw x 

你原来test功能的分支机构分布在实例之中。

一些替代技巧涉及使用class-associated data types(向编译器证明数据类型在所有实例之间共享)或view patterns(它允许您概括模式匹配)。


查看模式

我们可以使用视图模式来清理模式匹配和类型的类的实例,有点之间的连接,让我们通过模式上的共享匹配近似的图案跨实例匹配类型。

下面是一个例子,我们写了一个函数,有两种情况,让我们对类中的任何事物进行模式匹配。

{-# LANGUAGE ViewPatterns #-} 

class C a where 
    view  :: a -> View 

data View = One Int 
      | Two Int Int 

data MyType1 = MyObj11 Int | MyObj12 Int Int 

instance C MyType1 where 
    view (MyObj11 n) = One n 
    view (MyObj12 n m) = Two n m 

data MyType2 = MyObj21 Int | MyObj22 Int Int 

instance C MyType2 where 
    view (MyObj21 n) = One n 
    view (MyObj22 n m) = Two n m 

test :: C a => a -> String 
test (view -> One n) = "One " ++ show n 
test (view -> Two n m) = "Two " ++ show n ++ show m 

注意->语法如何让我们在每一个实例回调到合适的view功能,查找每类自定义数据类型的编码,以模式匹配就可以了。

设计的挑战是要拿出捕获所有的行为变种你感兴趣的视图类型。

在你原来的问题,你想每一个构造有不同的行为,所以实际上没有使用视图类型的原因(在每个实例中直接调度到该行为已经足够好)。

+0

好吧,看起来这个语句是为什么的开始:“当你在一个显式的构造函数上进行模式匹配时,你会提交一个特定的数据类型表示。”好的,那为什么呢?为什么模式匹配会导致此承诺在该点输入? – mentics 2011-04-22 22:46:48

+1

模式匹配解构*具体数据类型*。你选择一个特定的类型,并查看它的构造函数。这意味着您的代码不能再适用于所有类型。现在,您可以将我的上面的代码翻译成您可以同时对多种类型进行模式匹配的语法,但这不是Haskell的工作原理。不过这是一个有趣的想法。 – 2011-04-22 22:50:09

+0

我认为这个评论问题是,为什么Haskell不这样工作?为什么这种语言的这种特征是以这种限制性的方式设计的? – 2011-04-22 23:05:12

相关问题