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?

È stato utile?

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 [i .. j] per quanto sopra) è probabile che venga incluso in una versione futura del " versione della community " di OCaml , in modo che possa diventare idiomatico. Tuttavia, non ti consiglio di iniziare a giocare con le estensioni di sintassi se non conosci la lingua.

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)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top