反向范围实施

dop*_*man 9 haskell

为了记录,我是一个Haskell noob.我试图理解为什么范围可以声明为

[1..10] -- yields [1,2,3,4,5,6,7,8,9,10]
Run Code Online (Sandbox Code Playgroud)

并不是

[10..1] -- yields []
Run Code Online (Sandbox Code Playgroud)

看起来很简单,就像这样实现它:

(.:.) :: Enum a => a -> a -> [a]
(.:.) a b =
   | a == b = []
   | a > b = a : (a - 1) .:. b
   | a < b = a : (a + 1) .:. b
Run Code Online (Sandbox Code Playgroud)

我在这里不理解什么?

rec*_*nja 10

尝试[10,9..1]而不是[10..1]

[10..1] des to to to enumFromTo

[10,9..1] des to to to enumFromThenTo

观察GHCI中函数的行为:

Prelude> [10..1]
[]
Prelude> [10,9..1]
[10,9,8,7,6,5,4,3,2,1]
Prelude> :t enumFromTo
enumFromTo :: Enum a => a -> a -> [a]
Prelude> :t enumFromThenTo
enumFromThenTo :: Enum a => a -> a -> a -> [a]
Prelude> enumFromTo 10 1
[]
Prelude> :t enumFromThenTo 10 9 1
[10,9,8,7,6,5,4,3,2,1]
Run Code Online (Sandbox Code Playgroud)

您实现的新行为(.:.)很少是理想的默认行为,因为以这种方式生成的列表不能再始终假定为升序.因此,必须使用或明确降低意图.[x,(pred x)..y]enumFromThenTo


Rei*_*ton 6

几乎总是当你有一个类似的表达式[1..n],并且n碰巧是0时,你想要的是值[]而不是[1,0].例如考虑

factorial n = product [1..n]
Run Code Online (Sandbox Code Playgroud)

然后我们想要

factorial 0  ~~>  product [1..0]  ~~>  product []  ~~>  1   -- correct
Run Code Online (Sandbox Code Playgroud)

factorial 0  ~~>  product [1..0]  ~~>  product [1,0]  ~~>  0   -- oops
Run Code Online (Sandbox Code Playgroud)

这就是为什么[m..n]不生成降序列表的原因m > n.

(如果m >= n+2(例如,如果in [1..n],n则为负数)那么它很可能是一个错误条件,并且可能[m..n]应该是一个错误;但它仍然由语言标准定义[].)