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

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

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

Какая правильная идиома OCaml для этого?

4b9b3361

Ответ 1

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

# 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, так что может стать идиоматическим. Я не рекомендую вам начинать играть с расширениями синтаксиса, если вы новичок в этом языке.

Ответ 2

С Батареи включены, вы можете написать

let nums = List.of_enum (1--10);;

Оператор -- генерирует перечисление от первого значения ко второму. Оператор --^ аналогичен, но перечисляет полуоткрытый интервал (1--^10 будет перечислять от 1 до 9).

Ответ 3

Здесь вы идете:

let rec range i j = if i > j then [] else i :: (range (i+1) j)

Обратите внимание, что это не хвостовая рекурсия. Современные версии Python даже имеют ленивый диапазон.

Ответ 4

Это работает в базе OCaml:

# List.init 5 (fun x → x + 1);; -: int list = [1; 2; 3; 4; 5]

Ответ 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

Ответ 6

Если вы используете open Batteries (это версия сообщества стандартной библиотеки), вы можете сделать range(1,n+1) на List.range 1 `To n (обратите внимание на обратную кавычку перед To).

Более общий способ (также нужен аккумулятор) - использовать List.init n f, который возвращает список, содержащий (f 0) (f 1)... (f (n-1)).

Ответ 7

Немного поздно в игре здесь, но здесь моя реализация:

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, но это может быть лучше, если вам нужна только одна функция, и вы пытаетесь избежать полной структуры.

Ответ 8

Кстати, в Haskell вы предпочитаете использовать

enumFromTo 1 n
[1 .. n]

Это просто не нужно.

take n [1 ..]
take n $ iterate (+1) 1

Ответ 9

Вслед за Алексом Ковентри сверху, но еще короче.

let range n = List.init n succ;;    
> val range : int -> int list = <fun>   
range 3;;                           
> - : int list = [1; 2; 3]              

Ответ 10

Если вам не нужен параметр "step", один из простых способов реализовать эту функцию:

let range start stop = List.init(abs @@stop - start) (fun я → я + start)

Ответ 11

Придумали это:

let range a b =
  List.init (b - a) ((+) a)