我刚刚开始学习Haskell,并且对范围的行为感到惊讶。
我知道[1, 2 .. 10]
是enumFromThenTo 1 2 10
的语法糖。
从其他编程语言(例如Python)我习惯使用 first , last 和 step 参数指定范围,这样Haskell的然后就相当于Python中的 first + step 。
为什么Haskell使用然后而不是 step 来定义序列中值之间的间距?
答案 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
所以为那些难以手动实现的表达式添加语法糖/标准函数是有意义的。