haskell 模式匹配:常量和刚性类型变量

lndjwyie  于 9个月前  发布在  其他
关注(0)|答案(2)|浏览(107)

初学者的问题。
我在试着理解模式匹配是如何与常量一起工作的。

-- myF :: [a] -> [a]
myF ('p':'r':'e':_) = "Prefix"
myF (x:xs) = x:xs
myF [] = []

这编译和运行良好。但是,如果我取消注解试图指定函数类型的行,它会失败,并返回Couldn 't match expected type a' with actual type Char' `a' is a rigid type variable bound by the type signature for:myF::forall a.[a] -> [a]
https://godbolt.org/z/51oMGW4Ev
如果我正确理解了这个错误,它抱怨函数应该与任何类型一起工作,但是“pre”常量的特殊化只能返回String?
这是否意味着你不能“专门化”不同类型常量的函数?

myF ('p':'r':'e':_) = "Prefix"
myF (1:2:3:[]) = 0:[]

同样,并不是说这对任何事情都有用,只是希望理解模式匹配机制。
谢谢

btxsgosb

btxsgosb1#

Haskell被设计为可以在运行时不保留类型信息(在绝大多数情况下)。这样做有很好的理由,其中之一是优化(需要保留和传递的数据更少)。
也就是说,当我们调用一个函数

f :: [a] -> ...

f不接收任何关于a类型的信息。粗略地说,f被传递了一堆表示某个列表的“位”,但是f不知道编码列表元素的位是表示整数、字符还是其他任何东西。
实际上,列表[0,1]有可能(至少在理论上)具有与列表[False, True]相同的位级表示,因此f无法区分它们。连贯地,我们不能写

f [0,1] = [1,1,1]
f [x,y] = [x]  -- would match against [False, True]
...

模式匹配规则非常简单:我们只能和已知的类型进行匹配所以我们可以匹配Int s,(String, Bool),以此类推。我们不能匹配像a这样的类型变量,因为我们不知道它是什么。我们也可以部分匹配[a],但不能比列表“level”更深:我们可以匹配x:y:z:[],因为它只检查列表,但是x:True:[]也会匹配a类型的值,所以这是不可能的。
请注意,现代Haskell的一些高级功能(如GADT和Typeable)可以用于在运行时保留一些类型信息,因此上面看到的类似形式的“禁止f”成为可能。既然你说你是一个初学者,我建议你现在忽略这些高级功能。首先坚持基础知识,一旦你熟悉了它们,你就可以深入研究更复杂的功能。

thtygnil

thtygnil2#

这里使用('p': …),或者在规范形式((:)) 'p' (…))中使用(:) :: a -> [a] -> [a]数据构造函数。但是第一项是'p',这是一个Char值的模式。这意味着(:)数据构造函数的第一个参数是Char,因此('p': …)的类型是[Char],因此Char的列表是s。因此,项目的类型不能有 * 任何 * 类型a,而只能有Char s。
因此,这意味着模式的类型是[Char]String(这只是[Char]的别名)。
返回类型也是[Char](或String),因为"Prefix"是一个String,同样也适用于x : xs,因为x是一个Char,而xs是一个Char s的列表:

myF :: String -> String
myF ('p' : 'r' : 'e' : _) = "Prefix"
myF (x : xs) = x : xs
myF [] = []

这可以缩短为:

myF :: String -> String
myF ('p' : 'r' : 'e' : _) = "Prefix"
myF xs = xs

你不能实现一个函数:

myF ('p':'r':'e':_) = "Prefix"
myF (1:2:3:[]) = 0:[]

因为第一个子句要求输入类型为[Char],而第二个子句的类型为(Eq a, Num a) => [a]

相关问题