List Haskell中的递减范围

List Haskell中的递减范围,list,haskell,List,Haskell,我对哈斯克尔很陌生。有人能解释一下为什么这样定义一个列表会返回一个空列表吗 ghci> let myList = [10..1] ghci> myList [] 然而,这是正确的 ghci> let myList = [10, 9..1] ghci> myList [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] 基本上,因为[10..1]被翻译成enumFromTo 10 1,它本身的语义是通过从(包括)10向上计数(步长+1)得到小于1的所有

我对哈斯克尔很陌生。有人能解释一下为什么这样定义一个列表会返回一个空列表吗

ghci>  let myList = [10..1]
ghci>  myList
[]
然而,这是正确的

ghci>  let myList = [10, 9..1]
ghci>  myList
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

基本上,因为
[10..1]
被翻译成
enumFromTo 10 1
,它本身的语义是通过从(包括)
10
向上计数(步长
+1
)得到小于
1
的所有元素来创建一个列表

[10,9..1]
被翻译成
enumFromToThen 10 9 1
,它明确规定了计数步长为
9-10
,即
-1
(对于
enumFromTo
,它被硬编码为
+1

更准确的规范可在Haskell报告(6.3.4枚举类)中找到:

对于类型
Int
Integer
,枚举函数具有以下含义:

  • 来自e1的序列
    enumfrome1
    是列表
    [e1,e1+1,e1+2,…]

  • 序列
    enumFromThen e1 e2
    是列表
    [e1,e1+i,e1+2i,…]
    ,其中增量i为e2-e1。增量可以是零或负。如果增量为零,则所有列表元素都相同

  • 序列
    enumFromTo e1 e3
    是列表
    [e1,e1+1,e1+2,…e3]
    。如果
    e1>e3
    ,则列表为空

  • 从枚举到e1 e2 e3的序列
    是列表
    [e1,e1+i,e1+2i,…e3]
    ,其中增量
    i
    ,是
    e2-e1
    。如果增量为正或零,则当下一个元素大于e3时,列表终止;如果
    e1>e3
    ,则列表为空。如果增量为负值,则当下一个元素小于
    e3
    时,列表终止;如果
    e1
    ,则列表为空


基本上,因为
[10..1]
被翻译成
enumFromTo 10 1
,它本身的语义是通过从(包括)
10
向上计数(步长
+1
)得到小于
1
的所有元素来创建一个列表

[10,9..1]
被翻译成
enumFromToThen 10 9 1
,它明确规定了计数步长为
9-10
,即
-1
(对于
enumFromTo
,它被硬编码为
+1

更准确的规范可在Haskell报告(6.3.4枚举类)中找到:

对于类型
Int
Integer
,枚举函数具有以下含义:

  • 来自e1的序列
    enumfrome1
    是列表
    [e1,e1+1,e1+2,…]

  • 序列
    enumFromThen e1 e2
    是列表
    [e1,e1+i,e1+2i,…]
    ,其中增量i为e2-e1。增量可以是零或负。如果增量为零,则所有列表元素都相同

  • 序列
    enumFromTo e1 e3
    是列表
    [e1,e1+1,e1+2,…e3]
    。如果
    e1>e3
    ,则列表为空

  • 从枚举到e1 e2 e3的序列
    是列表
    [e1,e1+i,e1+2i,…e3]
    ,其中增量
    i
    ,是
    e2-e1
    。如果增量为正或零,则当下一个元素大于e3时,列表终止;如果
    e1>e3
    ,则列表为空。如果增量为负值,则当下一个元素小于
    e3
    时,列表终止;如果
    e1
    ,则列表为空


算术序列表示法只是类中函数的语法糖

至于为什么它们没有被定义为自动反转,我只能推测,但以下是一些可能的原因:

  • 如果在别处定义了
    a
    b
    ,那么很难一目了然地判断
    [a..b]
    将朝哪个方向发展

  • 它有更好的数学性质来推理。您不必为顺序颠倒添加特殊情况


算术序列表示法只是类中函数的语法糖

至于为什么它们没有被定义为自动反转,我只能推测,但以下是一些可能的原因:

  • 如果在别处定义了
    a
    b
    ,那么很难一目了然地判断
    [a..b]
    将朝哪个方向发展

  • 它有更好的数学性质来推理。您不必为顺序颠倒添加特殊情况


如果您希望生成从
a
b
的列表,而不管
a
,您都可以使用以下命令:


[a,a+(signum$b-a)…b]

如果要生成从
a
b
的列表,无论
a
,都可以使用以下命令:

[a,a+(signum$b-a)…b]

适用于新手

要列出从20到1的所有数字,你不能只做

[20..1]
您必须这样指定:

[20,19..1]
适用于新手

要列出从20到1的所有数字,你不能只做

[20..1]
您必须这样指定:

[20,19..1]

谢谢,这很有道理。乍一看,我认为这是一个相当愚蠢的符号,但现在我可以看到,它使得定义范围内的步长大小成为可能。很酷!现在对哈斯克尔非常兴奋:)谢谢,这是有道理的。乍一看,我认为这是一个相当愚蠢的符号,但现在我可以看到,它使得定义范围内的步长大小成为可能。很酷!现在对Haskell非常兴奋:)注意,如果
a
enumFrom       :: a -> [a]            -- [n..]
enumFromThen   :: a -> a -> [a]       -- [n,n'..]
enumFromTo     :: a -> a -> [a]       -- [n..m]
enumFromThenTo :: a -> a -> a -> [a]  -- [n,n'..m]
[a..]     = enumFrom a
[a..b]    = enumFromTo a b
[a, b..]  = enumFromThen a b
[a, b..c] = enumFromThenTo a b c