men*_*ics 14 haskell pattern-matching typeclass
请参阅下面的代码示例 它不会编译.我原以为可能是因为它必须为测试函数中的第一个参数设置一个类型.但是,这没有任何意义,因为如果我不这么做模式匹配上它,所以它会编,我可以既把它MyObj11 5和MyObj21 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.
Run Code Online (Sandbox Code Playgroud)
Don*_*art 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
Run Code Online (Sandbox Code Playgroud)
您原始test函数的分支现在分布在实例中.
一些替代技巧涉及使用与类相关的数据类型(向编译器证明数据类型在所有实例之间共享)或视图模式(可以概括模式匹配).
查看模式
我们可以使用视图模式来清除模式匹配和类型类实例之间的连接,允许我们通过共享类型上的模式匹配来近似跨实例的模式匹配.
这是一个例子,我们编写一个函数,有两个案例,它们允许我们模式匹配类中的任何东西.
{-# 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
Run Code Online (Sandbox Code Playgroud)
请注意->语法如何让我们view在每个实例中回调正确的函数,查找每种类型的自定义数据类型编码,以便对其进行模式匹配.
设计挑战是提出一种视图类型,捕获您感兴趣的所有行为变体.
在您的原始问题中,您希望每个构造函数都有不同的行为,因此实际上没有理由使用视图类型(在每个实例中直接调度该行为已经足够好了).