Какая идиома OCaml эквивалентна функции диапазона Python?
Вопрос
Я хочу создать список целых чисел от 1 до n. Я могу сделать это в Python, используя range (1, n + 1), и в Haskell, используя: take n (iterate (1+) 1). Р>
Какая идиома OCaml для этого?
Решение
Я не знаю идиомы, но вот довольно естественное определение, использующее оператор инфикса:
# let (--) i j =
let rec aux n acc =
if n < i then acc else aux (n-1) (n :: acc)
in aux j [] ;;
val ( -- ) : int -> int -> int list = <fun>
# 1--2;;
- : int list = [1; 2]
# 1--5;;
- : int list = [1; 2; 3; 4; 5]
# 5--10;;
- : int list = [5; 6; 7; 8; 9; 10]
Кроме того, расширение синтаксиса пониманий (которое дает синтаксис [i .. j]
для вышеупомянутого), вероятно, будет включен в будущий выпуск " версия сообщества " OCaml , так что может стать идиоматическим. Я не рекомендую начинать играть с расширениями синтаксиса, если вы новичок в этом языке.
Другие советы
С батареями в комплекте вы можете писать
let nums = List.of_enum (1--10);;
Оператор -
генерирует перечисление из первого значения во второе. Оператор - ^
аналогичен, но перечисляет полуоткрытый интервал ( 1 - ^ 10
будет перечислять от 1 до 9).
Вот, пожалуйста.
let rec range i j = if i > j then [] else i :: (range (i+1) j)
Обратите внимание, что это не хвостовая рекурсия. Современные версии Python даже имеют ленивый диапазон.
Это работает в базе OCaml:
<код> & # 65283; List.init 5 (весело x -> x + 1) ;; -: int list = [1; 2; 3; 4; 5] Код>
OCaml имеет специальный синтаксис для сопоставления с образцом в диапазонах:
let () =
let my_char = 'a' in
let is_lower_case = match my_char with
| 'a'..'z' -> true (* Two dots define a range pattern *)
| _ -> false
in
printf "result: %b" is_lower_case
Чтобы создать диапазон, вы можете использовать Core
:
List.range 0 1000
Если вы используете open Batteries
(это версия стандартной библиотеки для сообщества), вы можете сделать range (1, n + 1)
списком .range 1 `To n
(обратите внимание на обратную цитату перед To
).
Более общий способ (также требующий батарей) - использовать List.init nf
, который возвращает список, содержащий (f 0) (f 1) ... (f (n-1)) , Р>
Немного опоздал к игре, но вот моя реализация:
let rec range ?(start=0) len =
if start >= len
then []
else start :: (range len ~start:(start+1))
Затем вы можете использовать его очень похоже на функцию python:
range 10
(* equals: [0; 1; 2; 3; 4; 5; 6; 7; 8; 9] *)
range ~start:(-3) 3
(* equals: [-3; -2; -1; 0; 1; 2] *)
Естественно, я думаю, что лучший ответ - просто использовать Core, но это может быть лучше, если вам нужна только одна функция, и вы пытаетесь избежать полной структуры.
Кстати, в Haskell вы бы предпочли использовать
enumFromTo 1 n
[1 .. n]
Это просто не нужно.
take n [1 ..]
take n $ iterate (+1) 1
Вслед за Алексом Ковентри сверху, но еще короче. Р>
let range n = List.init n succ;;
> val range : int -> int list = <fun>
range 3;;
> - : int list = [1; 2; 3]
Если вам не нужен " шаг " параметр, один простой способ реализовать эту функцию будет:
let range start stop = List.init (abs @@ stop - start) (забавно i -> i + start)