您可以在类型类约束参数上对构造函数进行模式匹配吗?
请参阅下面的代码示例。它不会编译。我原以为可能是因为测试函数中的第一个参数必须具有单一类型。但这没有意义,因为如果我不对其进行模式匹配,那么它就会编译,我可以使用 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.
See code example below. It won't compile. I had thought that maybe it's because it has to have a single type for the first parameter in the test function. But that doesn't make sense because if I don't pattern match on it so it will compile, I can call it with both MyObj11 5
and MyObj21 5
which are two different types.
So what is it that restricts so you can't pattern match on constructors with a type class constrained parameter? Or is there some mechanism by which you can?
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
当您对显式构造函数进行模式匹配时,您将提交特定的数据类型表示。该数据类型并非在类的所有实例之间共享,因此根本不可能以这种方式编写适用于所有实例的函数。
相反,您需要将所需的不同行为与每个实例关联起来,如下所示:
原始
test
函数的分支现在分布在实例中。一些替代技巧涉及使用类关联数据类型(向编译器证明数据类型在所有实例之间共享),或视图模式(它可以让您概括模式匹配)。
视图模式
我们可以使用视图模式来稍微清理模式匹配和类型类实例之间的连接,从而允许我们通过共享类型上的模式匹配来近似跨实例的模式匹配。
这是一个示例,我们编写一个函数,有两种情况,让我们可以对类中的任何内容进行模式匹配。
请注意
->
语法如何让我们在每个实例中回调正确的view
函数,查找每种类型的自定义数据类型编码,以便进行模式匹配在它上面。设计挑战是提出一个视图类型来捕获您感兴趣的所有行为变体。
在您最初的问题中,您希望每个构造函数都有不同的行为,因此实际上没有理由使用视图类型(调度直接针对每个实例中的行为已经足够好了)。
When you pattern match on an explicit constructor, you commit to a specific data type representation. This data type is not shared among all instances of the class, and so it is simply not possible to write a function that works for all instances in this way.
Instead, you need to associate the different behaviors your want with each instance, like so:
The branches of your original
test
function are now distributed amongst the instances.Some alternative tricks involve using class-associated data types (where you prove to the compiler that a data type is shared amongst all instances), or view patterns (which let you generalize pattern matching).
View patterns
We can use view patterns to clean up the connection between pattern matching and type class instances, a little, allowing us to approximate pattern matching across instances by pattern matching on a shared type.
Here's an example, where we write one function, with two cases, that lets us pattern match against anything in the class.
Note how the
->
syntax lets us call back to the rightview
function in each instance, looking up a custom data type encoding per-type, in order to pattern match on it.The design challenge is to come up with a view type that captures all the behavior variants you're interested in.
In your original question, you wanted every constructor to have a different behavior, so there's actually no reason to use a view type (dispatching directly to that behavior in each instance already works well enough).