我正在学习haskell并且已经编写了各种相当简单的函数来处理语言。我写了这个函数:
doubleOneOrTail :: [t]->[t]
doubleOneOrTail [x] = [x,x]
doubleOneOrTail (x:xs) = xs
究竟是什么说的。将1个元素的列表加倍,或返回多个元素列表的尾部。这个通用语法适用于单个元素列表或列表列表等。我可以将此函数重写为以下内容:
doubleOneOrTail :: [[t]]->[[t]]
doubleOneOrTail [[x]] = [[x,x]]
doubleOneOrTail (x:xs) = xs
如果输入以下内容,则会抛出错误:
doubleOneOrTail [1,2,3]
但确实接受了这个:
doubleOneOrTail [[[[1,2,3],[2]]]]
将其视为具有单个元素的列表(该元素是列表列表)并将其加倍。
显然,模式[a] - > [a]不匹配单个元素的列表,但在某种程度上匹配任何列表顺序。 Wh [[a]] - > [[a]]也匹配多个列表顺序(尽管不是单个元素的列表)。如果有人能解释这是如何工作的,将不胜感激。
第二个问题是,有可能(或者甚至需要)具有专门接受列表的特定顺序的函数声明。只说清单列表?
答案 0 :(得分:3)
听起来你对这里令人惊讶的事情有了很好的理解:[a]
是任何类型的事物的列表,包括列表列表。您可以手动解决类型推断器自动执行的操作。假设,使用您的第一个定义,我们写道:
let xs = [[[1,2], [3,4]], [[5]]]
in doubleOneOrTail xs
此时GHC必须确保这些类型与我们匹配。
xs :: [[[Integer]]] -- really could be any Num type, but assume Integer
既然我们以doubleOneOrTail
作为参数调用[[[Integer]]]
,GHC必须统一类型[a]
和[[[Integer]]]
,这意味着找到一些具体的类型来代替a
,使两种类型相匹配。只有一个正确的答案:
[a] ~ [[[Integer]]]
a ~ [[Integer]]
因此,我们将事物列表加倍或拖尾,其中每个事物都是数字列表的列表。由于类型确实统一,GHC给出了全明确的函数调用编译,因此我们得到[[[5]]]
。
关于你的第二个问题,你是否可以或应该限制特定深度的名单:通常你不应该。这种函数称为参数化多态,这意味着它适用于任何类型的a
,无论它是什么;这是一个有用的属性,在可能的情况下保留是很好的。如果您的函数不需要查看其a
类型的值以便正确执行,那么它应该允许它们为任何类型。
假设您仍想限制其类型?我不知道如何将其限制在深度列表中而不添加其他一些附带限制。例如,您可以说它必须是数字列表(并希望没有人为列表定义Num
实例!):
doubleOneOrTail :: Num a => [a] -> [a]
或者您可以将其限制为非常特定的类型,例如[Int]
。这样可以保证只能使用该类型调用它。
doubleOneOrTail :: [Int] -> [Int]
但如上所述,所有这些方法都不必要地限制了您的功能类型。最好尽可能一般地定义它,并找到一些其他方法来满足任何其他问题,使你想要限制它的类型。
答案 1 :(得分:0)
对@amalloy的回答很少。很可能你对Enum类约束没问题:
doupbleOneOrTrail :: (Enum t) => [t] -> [t]
所以你的函数接受字符,数字,布尔值等列表
λ: doubleOneOrTail "foo"
"oo"
λ: doubleOneOrTail [False]
[False,False]