为什么Haskell的范围语法首先使用而不是使用First和Step?

时间:2017-03-14 14:01:26

标签: haskell range

我刚刚开始学习Haskell,并且对范围的行为感到惊讶。

我知道[1, 2 .. 10]enumFromThenTo 1 2 10的语法糖。

从其他编程语言(例如Python)我习惯使用 first last step 参数指定范围,这样Haskell的然后就相当于Python中的 first + step

为什么Haskell使用然后而不是 step 来定义序列中值之间的间距?

3 个答案:

答案 0 :(得分:8)

请注意,例如Python的范围说明符是函数

>>> range(1, 12, 2)
[1, 3, 5, 7, 9, 11]

Haskell的目标是提供一种语法,从字面上看,你可能会写出另一个人的列表,编写..而不是“明显的”模式:

ghci> [1, 3 .. 11]
[1,3,5,7,9,11]

另一点(由Carl在评论leftaroundabout的答案中提出)是序列语法可以用于非数字类型,其中没有这么简单的方法来编写“步骤”:

ghci> ['a', 'f' .. 'z']
"afkpuz"

答案 1 :(得分:5)

以Ben和Carl所说的为基础:

Enum中定义的函数是多态的,例如

λ> :t enumFromThenTo
enumFromThenTo :: Enum a => a -> a -> a -> [a]

并将它们定义为"第一个,第二个,最后一个",我们可以对所有参数使用相同的多态类型参数a

如果我们将它们定义为" first,last,step",那么step参数可能与其他两个参数的类型不同。

  • 对于整数序列,该步骤也是整数 - 没问题。
  • 对于一个字符序列,该步骤又是一个整数 - 所以我们可以将step的类型固定为某种整数类型? (但是哪一个?)
  • 但是没有 - 对于浮动序列,步骤也需要是浮点数!

所以我们需要(我认为!)将另一个类型变量添加到Enum类型类中,这将使它变得更加复杂,并且(可能 - 未经检查)需要GHC扩展而不是比标准的Haskell。

答案 2 :(得分:4)

我同意,IMO start-step-end本来是更好的惯例。然而,开始 - 结束更常见于纯粹的数学语境中,以及Haskell的遗产。

请注意,您可以轻松地手动实现

  • 启动步骤端:

    takeWhile (<end+step/2) $ iterate (+step) start
    
  • 开始步数:

    take count $ iterate (+step) start
    

而start-then-end需要先手动计算步骤

let step = then - start
in takeWhile (< end+step/2) $ iterate (+step) start

所以为那些难以手动实现的表达式添加语法糖/标准函数是有意义的。