函数声明中列表模式的语法

时间:2017-03-27 20:42:09

标签: haskell

我正在学习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]]也匹配多个列表顺序(尽管不是单个元素的列表)。如果有人能解释这是如何工作的,将不胜感激。

第二个问题是,有可能(或者甚至需要)具有专门接受列表的特定顺序的函数声明。只说清单列表?

2 个答案:

答案 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]