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

StackOverflow https://stackoverflow.com/questions/243864

  •  04-07-2019
  •  | 
  •  

Вопрос

Я хочу создать список целых чисел от 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)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top