Haskell 您能在类型类约束参数上匹配模式构造函数吗?

Haskell 您能在类型类约束参数上匹配模式构造函数吗?,haskell,pattern-matching,typeclass,Haskell,Pattern Matching,Typeclass,请参见下面的代码示例。它不会编译。我曾经认为这可能是因为测试函数中的第一个参数必须有一个单一的类型。但这没有意义,因为如果我不匹配它的模式,它就会编译,我可以用两种不同类型的MyObj11 5和MyObj21 5调用它 那么,是什么限制了您不能在具有类型类约束参数的构造函数上进行模式匹配呢?或者有什么机制可以帮助你 class SomeClass a where toString :: a -> String instance SomeClass MyType1 where toStri

请参见下面的代码示例。它不会编译。我曾经认为这可能是因为测试函数中的第一个参数必须有一个单一的类型。但这没有意义,因为如果我不匹配它的模式,它就会编译,我可以用两种不同类型的
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.
是什么限制了您不能在具有类型类约束参数的构造函数上进行模式匹配

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

相反,您需要将所需的不同行为与每个实例相关联,如下所示:

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
函数的分支现在分布在实例中

一些替代技巧涉及使用(向编译器证明一个数据类型在所有实例之间共享),或者(让您概括模式匹配)


查看模式

我们可以使用视图模式稍微清理一下模式匹配和类型类实例之间的连接,允许我们通过共享类型上的模式匹配来近似实例之间的模式匹配

这里有一个例子,我们写了一个函数,有两个案例,让我们的模式匹配类中的任何东西

{-# 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
请注意
->
语法如何让我们在每个实例中调用右侧的
视图
函数,查找每个类型的自定义数据类型编码,以便对其进行模式匹配

设计的挑战是找到一种视图类型,它可以捕获您感兴趣的所有行为变体


在最初的问题中,您希望每个构造函数都有不同的行为,因此实际上没有理由使用视图类型(在每个实例中直接分派到该行为已经足够好了)。

如果haskell的类是可关闭的,这可能是有意义的,也就是说,您可以为每个实现指定行为。但是Haskell类是开放的-当
实例SomeClass someonelsetype where toString v=“mwahahahah”
时,如果给定类型为
someonelsetype
的值,那么
测试应该做什么?Don的答案是处理这个问题的正确方法。这个问题对我来说似乎很明显:它会按照模式匹配的要求去做。如果没有模式匹配,它会像其他类似情况一样给出这样的错误。我看不出有什么区别。好吧,这条语句似乎是为什么的开始:“当您在显式构造函数上进行模式匹配时,您将提交到一个特定的数据类型表示。”好吧,那个么为什么会这样呢?为什么模式匹配会导致这种对类型的承诺呢?模式匹配解构了一种具体的数据类型。选择一个特定类型,并查看其构造函数。这意味着您的代码不能再适用于所有类型。现在,您可以想象将我上面的代码翻译成您同时进行多类型模式匹配的语法,但Haskell不是这样工作的。不过这是一个有趣的想法。我相信评论的问题是,为什么Haskell不这样工作?为什么语言的这个特性是以这种限制性的方式设计的呢?嗯。我的观点是:这可以追溯到ML,在数据类型上归纳地编写函数。我们通过引入一个数据类型进行设计,并通过对结构的归纳来解构它。“FP”就是这样做的。现在,对于类型类,这有点混淆,因为函数现在是在多个数据类型上编写的,但我们放弃了具体的模式匹配来支持这一点。视图模式在某种程度上纠正了这一点(另请参见“开放数据类型”的研究)。TL;DR:类型类和模式匹配并不是完全统一的,因为考虑到历史背景,这不是一件显而易见的事情。感谢您提供的视图模式示例。如果您有多组构造函数,并且希望它们具有相同的行为,那么可以使用该示例,这样就不必在所有实例中编写行为。虽然实例仍然需要编写,并且它们可以指向一个共享函数,所以。。。也许我不认为它在哪里特别有用。