Какая идиома OCaml эквивалентна функции диапазона Python? - PullRequest
24 голосов
/ 28 октября 2008

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

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

Ответы [ 10 ]

25 голосов
/ 28 октября 2008

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

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

13 голосов
/ 28 мая 2010

С батареями в комплекте , вы можете написать

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

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

11 голосов
/ 28 октября 2008

Вот, пожалуйста:

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

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

4 голосов
/ 11 апреля 2018

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

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

3 голосов
/ 07 октября 2015

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
2 голосов
/ 19 марта 2016

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

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

2 голосов
/ 28 декабря 2014

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

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

1 голос
/ 22 апреля 2019

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

let range n = List.init n succ;;    
> val range : int -> int list = <fun>   
range 3;;                           
> - : int list = [1; 2; 3]              
1 голос
/ 28 октября 2008

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

enumFromTo 1 n
[1 .. n]

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

take n [1 ..]
take n $ iterate (+1) 1
0 голосов
/ 26 апреля 2018

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

let range start stop = List.init (abs @@ stop - start) (fun i -> i + start)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...