函数(事实上,你完全正确的实现)
myList (x:y:z:xs) = y:z:x:(myList xs)
myList [] = []
myList [x] = [x]
足够通用,不依赖于列表中元素的类型为Integral a => a。所以如果你让 Haskell 推断它的类型,它会推断出[a] -> [a]。如果您将类型限制为Integral a => [a] -> [a],它仍然可以工作,但不那么通用,这会将使用限制为整数类型。
下面是原理的演示:
Prelude> :{
Prelude| let myList (x:y:z:xs) = y:z:x:(myList(xs))
Prelude| myList [] = []
Prelude| myList [x] = [x]
Prelude| :}
Prelude> :t myList
myList :: [a] -> [a]
Prelude> take 15 $ myList ['a'..]
"bcaefdhigkljnom"
Prelude> take 15 $ myList [1..]
[2,3,1,5,6,4,8,9,7,11,12,10,14,15,13]
但是
Prelude> :{
Prelude| let myList :: Integral a => [a] -> [a]
Prelude| myList (x:y:z:xs) = y:z:x:(myList(xs))
Prelude| myList [] = []
Prelude| myList [x] = [x]
Prelude| :}
Prelude> :t myList
myList :: Integral a => [a] -> [a]
Prelude> take 15 $ myList [1..]
[2,3,1,5,6,4,8,9,7,11,12,10,14,15,13]
Prelude> take 15 $ myList ['a'..]
<interactive>:34:11:
No instance for (Integral Char) arising from a use of ‘myList’
In the second argument of ‘($)’, namely ‘myList ['a' .. ]’
In the expression: take 15 $ myList ['a' .. ]
In an equation for ‘it’: it = take 15 $ myList ['a' .. ]
所以重点是,两个定义是等价的,并且能够做同样的事情,但是约束类型签名(我会说不合理)不如其他定义有用具有通用类型签名的那个。
如果分配需要Integral a => [a] -> [a] 类型的函数,您真正需要做的只是用该类型签名准确地注释您已经拥有的函数。但是,没有(合理/合理的)方法可以以某种方式引导 Haskell 从函数定义中推断出该类型,因为这将需要以某种方式间接指示列表必须包含支持 Integral 中的操作的类型的值。 ..亚达亚达。
最后一点:您的实现/算法完全正确,但在类型签名和通用性概念方面存在不足。
编辑:如果你真正需要的不是一个函数而是一个列表(你的问题在这方面有点模棱两可),你需要做的就是重命名myList的以下定义例如myList' 或 go(我认为这是嵌套递归助手的典型名称)或其他东西(可以但不必隐藏在列表 myList 中),然后将 [1..] 传递给它,将结果分配给myList:
myList :: Integral a => [a]
myList = go [1..]
where go (x:y:z:xs) = y:z:x:(go xs)
go [] = []
go [x] = [x]
当然是这样看的,Integral a => [a] 是确实是列表的一个非常通用的签名(但不是最通用的,这将是 (Enum a, Num a) => [a],正如我被 dfeuer 的评论所引导的那样),因为a 的类型不能由传递给函数的输入类型来确定,因为你总是在传递[1..]。