Какая идиома OCaml эквивалентна функции диапазона Python?

Я хочу создать список целых чисел от 1 до n. Я могу сделать это в Python, используя range (1, n + 1), и в Haskell, используя: take n (iterate (1+) 1).

Какая идиома OCaml подходит для этого?

Синтаксис Haskell будет следующим: [1..n].

yfeldblum 29.10.2008 19:02
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
25
1
14 292
13
Перейти к ответу Данный вопрос помечен как решенный

Ответы 13

Ну вот:

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]. Измените> на> =.

Darius Bacon 29.10.2008 19:45

@DariusBacon Нет, ты ошибаешься. Функции range возвращают генераторы, а не списки. Это основная проблема всех представленных здесь решений (все они требуют, чтобы среда выполнения выделяла место для некоторых int).

Gark Garcia 28.01.2020 22:51
Ответ принят как подходящий

Я не знаю идиомы, но вот довольно естественное определение с использованием инфиксного оператора:

# 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

Thelema 28.10.2008 20:35

Оператор -- реализован в Batteries Included, хотя он производит перечисление, а не список.

Michael Ekstrand 14.08.2010 15:44

Функция диапазона Python не включает верхнюю границу, как ваша, но ее достаточно легко исправить, вызвав aux с (j-1) вместо j

Nate Parsons 18.11.2012 07:51

Вопрос просит «создать список целых чисел от 1 до n», чтобы не дублировать поведение range (1, n) в Python. Предлагаемое вами изменение не является естественным определением оператора (-).

Chris Conway 18.11.2012 19:20

почему вы закомментировали первую строчку? # let (--) i j = ?

Clojurevangelist 08.04.2020 21:10

Это не комментарий, это командная строка в интерактивной среде OCaml. Обнаружение синтаксиса работает не очень хорошо.

Chris Conway 10.04.2020 20:46

Кстати, в 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 13.08.2010 06:01

@aneccodeal Нет. OCaml не допускает операторов, начинающихся с '.' (хотя они могут содержать "." после первого символа). Допустимые символы для операторов определены в лексической документации OCaml здесь: caml.inria.fr/pub/docs/manual-ocaml/lex.html

Michael Ekstrand 14.08.2010 15:42

Если вы используете 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.

Jonathan Ballet 05.05.2019 18:24

Если вам не нужен параметр "шаг", простой способ реализовать эту функцию:

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 не является ключевым словом лямбда

cdaringe 12.09.2020 21:38

Лично я использую для этого библиотеку диапазонов 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);;

Другие вопросы по теме