Подтвердить что ты не робот

Сокращение диапазонов в Haskell

Я очень новичок в 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]
4b9b3361

Ответ 1

В принципе, поскольку [10..1] переводится на enumFromTo 10 1, который сам имеет семантику для создания списка, беря все элементы меньше, чем 1, которые являются результатом подсчета вверх (с размером шага +1) из ( в том числе) 10.

В то время как [10, 9..1] переводится на enumFromToThen 10 9 1, который явно устанавливает размер шага подсчета как 9-10, т.е. -1 (который жестко закодирован до +1 для enumFromTo)

Более точная спецификация может быть найдена в отчете Haskell (6.3.4 Класс Enum):

enumFrom       :: a -> [a]            -- [n..]
enumFromThen   :: a -> a -> [a]       -- [n,n'..]
enumFromTo     :: a -> a -> [a]       -- [n..m]
enumFromThenTo :: a -> a -> a -> [a]  -- [n,n'..m]

Для типов Int и Integer функции перечисления имеют следующий смысл:

  • Последовательность enumFrom e1 - это список [e1,e1+1,e1+2,...].

  • Последовательность enumFromThen e1 e2 представляет собой список [e1,e1+i,e1+2i,...], где приращение я является e2-e1. Инкремент может быть нулем или отрицательным. Если приращение равно нулю, все элементы списка одинаковы.

  • Последовательность enumFromTo e1 e3 - это список [e1,e1+1,e1+2,...e3]. Список пуст, если e1 > e3.

  • Последовательность enumFromThenTo e1 e2 e3 - это список [e1,e1+i,e1+2i,...e3], где приращение i равно e2-e1. Если приращение положительное или ноль, список заканчивается, когда следующий элемент будет больше, чем e3; список пуст, если e1 > e3. Если приращение отрицательное, список заканчивается, когда следующий элемент будет меньше e3; список пуст, если e1 < e3.

Ответ 2

Арифметическая последовательность обозначений - это просто синтаксический сахар для функций из класса Enum.

[a..]     = enumFrom a
[a..b]    = enumFromTo a b
[a, b..]  = enumFromThen a b
[a, b..c] = enumFromThenTo a b c

Что касается того, почему они не были определены для автоматического изменения, я могу только догадываться, но вот несколько возможных причин:

  • Если a и b определены в другом месте, было бы труднее сказать с первого взгляда, в каком направлении [a..b] будет идти.

  • У него более хорошие математические свойства. Вам не нужно добавлять специальные случаи, когда последовательность будет отменена.

Ответ 3

Если вы хотите сгенерировать список от a до b, независимо от того, a < b, вы можете использовать следующее:

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