Qual è il linguaggio OCaml equivalente alla funzione range di Python?
Domanda
Voglio creare un elenco di numeri interi da 1 a n. Posso farlo in Python usando range (1, n + 1), e in Haskell usando: take n (iterate (1+) 1).
Qual è il giusto linguaggio OCaml per questo?
Soluzione
Non esiste un linguaggio che io conosca, ma ecco una definizione abbastanza naturale che utilizza un operatore infix:
# 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]
In alternativa, comprende l'estensione di sintassi (che fornisce alla sintassi
Altri suggerimenti
Con Batterie incluse , puoi scrivere
let nums = List.of_enum (1--10);;
L'operatore -
genera un'enumerazione dal primo valore al secondo. L'operatore - ^
è simile, ma enumera un intervallo semi-aperto ( 1 - ^ 10
verrà enumerato da 1 a 9).
Ecco qua:
let rec range i j = if i > j then [] else i :: (range (i+1) j)
Nota che questo non è ricorsivo di coda. Le moderne versioni di Python hanno persino una gamma pigra.
Funziona in OCaml di base:
# List.init 5 (fun x - > x + 1) ;;
-: int list = [1; 2; 3; 4; 5]
OCaml ha una sintassi speciale per la corrispondenza dei pattern sugli intervalli:
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
Per creare un intervallo, puoi utilizzare Core
:
List.range 0 1000
Se usi batterie aperte
(che è una versione comunitaria della libreria standard), puoi fare range (1, n + 1)
per List .range 1 `To n
(nota il backquote prima di To
).
Un modo più generale (anche bisogno di batterie) è usare List.init nf
che restituisce un elenco contenente (f 0) (f 1) ... (f (n-1)) .
Un po 'tardi al gioco qui, ma ecco la mia implementazione:
let rec range ?(start=0) len =
if start >= len
then []
else start :: (range len ~start:(start+1))
È quindi possibile utilizzarlo in modo molto simile alla funzione 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] *)
naturalmente penso che la risposta migliore sia semplicemente usare Core, ma questo potrebbe essere migliore se hai solo bisogno di una funzione e stai cercando di evitare il framework completo.
A proposito, in Haskell preferiresti usare
enumFromTo 1 n
[1 .. n]
Questi sono semplicemente superflui.
take n [1 ..]
take n $ iterate (+1) 1
Seguendo Alex Coventry dall'alto, ma anche più breve.
let range n = List.init n succ;;
> val range : int -> int list = <fun>
range 3;;
> - : int list = [1; 2; 3]
Se non hai bisogno di un " passaggio " parametro, un modo semplice per implementare questa funzione sarebbe:
let range start stop = List.init (abs @@ stop - start) (fun i - > i + start)