初学者的问题。
我在试着理解模式匹配是如何与常量一起工作的。
-- 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:[]
同样,并不是说这对任何事情都有用,只是希望理解模式匹配机制。
谢谢
2条答案
按热度按时间btxsgosb1#
Haskell被设计为可以在运行时不保留类型信息(在绝大多数情况下)。这样做有很好的理由,其中之一是优化(需要保留和传递的数据更少)。
也就是说,当我们调用一个函数
f
不接收任何关于a
类型的信息。粗略地说,f
被传递了一堆表示某个列表的“位”,但是f
不知道编码列表元素的位是表示整数、字符还是其他任何东西。实际上,列表
[0,1]
有可能(至少在理论上)具有与列表[False, True]
相同的位级表示,因此f
无法区分它们。连贯地,我们不能写模式匹配规则非常简单:我们只能和已知的类型进行匹配所以我们可以匹配
Int
s,(String, Bool)
,以此类推。我们不能匹配像a
这样的类型变量,因为我们不知道它是什么。我们也可以部分匹配[a]
,但不能比列表“level”更深:我们可以匹配x:y:z:[]
,因为它只检查列表,但是x:True:[]
也会匹配a
类型的值,所以这是不可能的。请注意,现代Haskell的一些高级功能(如GADT和
Typeable
)可以用于在运行时保留一些类型信息,因此上面看到的类似形式的“禁止f
”成为可能。既然你说你是一个初学者,我建议你现在忽略这些高级功能。首先坚持基础知识,一旦你熟悉了它们,你就可以深入研究更复杂的功能。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的列表:这可以缩短为:
你不能实现一个函数:
因为第一个子句要求输入类型为
[Char]
,而第二个子句的类型为(Eq a, Num a) => [a]
。