





Ну вот:
let rec range i j = if i > j then [] else i :: (range (i+1) j)
Обратите внимание, что это не хвостовая рекурсия. В современных версиях Python даже есть ленивый диапазон.
Не совсем так - Python range (1,3) возвращает [1,2], а ваш (диапазон 1 3) возвращает [1; 2; 3]. Измените> на> =.
@DariusBacon Нет, ты ошибаешься. Функции range возвращают генераторы, а не списки. Это основная проблема всех представленных здесь решений (все они требуют, чтобы среда выполнения выделяла место для некоторых int).
Я не знаю идиомы, но вот довольно естественное определение с использованием инфиксного оператора:
# 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, так что это может стать идиоматическим. Однако я не рекомендую начинать играть с расширениями синтаксиса, если вы новичок в этом языке.
ваша ссылка на сообщество ocaml должна указывать на: forge.ocamlcore.org/projects/batteries
Оператор -- реализован в Batteries Included, хотя он производит перечисление, а не список.
Функция диапазона Python не включает верхнюю границу, как ваша, но ее достаточно легко исправить, вызвав aux с (j-1) вместо j
Вопрос просит «создать список целых чисел от 1 до n», чтобы не дублировать поведение range (1, n) в Python. Предлагаемое вами изменение не является естественным определением оператора (-).
почему вы закомментировали первую строчку? # let (--) i j = ?
Это не комментарий, это командная строка в интерактивной среде OCaml. Обнаружение синтаксиса работает не очень хорошо.
Кстати, в Haskell вы бы предпочли использовать
enumFromTo 1 n
[1 .. n]
Это просто ненужно.
take n [1 ..]
take n $ iterate (+1) 1
С Батареи в комплекте вы можете написать
let nums = List.of_enum (1--10);;
Оператор -- генерирует перечисление от первого значения ко второму. Оператор --^ аналогичен, но перечисляет полуоткрытый интервал (1--^10 будет нумеровать от 1 до 9).
Не уверен, что мне нравится - для этого можно ли определить оператор ..?
@aneccodeal Нет. OCaml не допускает операторов, начинающихся с '.' (хотя они могут содержать "." после первого символа). Допустимые символы для операторов определены в лексической документации OCaml здесь: caml.inria.fr/pub/docs/manual-ocaml/lex.html
Если вы используете open Batteries (это версия стандартной библиотеки от сообщества), вы можете использовать range(1,n+1) с помощью List.range 1 `To n (обратите внимание на обратную цитату перед To).
Более общий способ (также требующий батарей) - использовать List.init n f, который возвращает список, содержащий (f 0) (f 1) ... (f (n-1)).
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
Немного поздно в игре, но вот моя реализация:
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, но это может быть лучше, если вам нужна только одна функция, и вы пытаетесь избежать использования полной структуры.
Это работает в базе OCaml:
# List.init 5 (fun x -> x + 1);;
- : int list = [1; 2; 3; 4; 5]
Обратите внимание, что List.init доступен, начиная с OCaml 4.06.0.
Если вам не нужен параметр "шаг", простой способ реализовать эту функцию:
let range start stop = List.init (abs @@ stop - start) (fun i -> i + start)
Следом за Алексом Ковентри сверху, но еще короче.
let range n = List.init n succ;;
> val range : int -> int list = <fun>
range 3;;
> - : int list = [1; 2; 3]
Придумал это:
let range a b =
List.init (b - a) ((+) a)
Если вы намереваетесь подражать ленивому поведению range, я бы рекомендовал использовать модуль Stream. Что-то типа:
let range (start: int) (step: int) (stop: int): int stream =
Stream.from (fn i -> let j = i * step + start in if j < stop then Some j else None)
fn -> весело. fn не является ключевым словом лямбда
Лично я использую для этого библиотеку диапазонов ocaml
(* print sum of all values between 1 and 50, adding 4 to all elements and excluding 53 *) Range.(from 1 50 |> map ((+) 4) |> filter ((!=) 53) |> fold (+) 0 |> print_int);;
Синтаксис Haskell будет следующим:
[1..n].