2015-07-12 20 views
5

Mi sto insegnando da solo a OCaml e le risorse principali che uso per la pratica sono alcuni problemi che Cornell ha reso disponibili dalla loro classe 3110. Uno dei problemi è scrivere una funzione per invertire un int (cioè: 1234 -> 4321, -1234 -> -4321, 2 -> 2, -10 -> -1 ecc.).Inversione di un int in OCaml

ho una soluzione di lavoro, ma sono preoccupato del fatto che non è esattamente idiomatica OCaml:

let rev_int (i : int) : int = 
    let rec power cnt value = 
    if value/10 = 0 then cnt 
    else power (10 * cnt) (value/10) in 
    let rec aux pow temp value = 
    if value <> 0 then aux (pow/10) (temp + (value mod 10 * pow)) (value/10) 
    else temp in 
    aux (power 1 i) 0 i 

Funziona correttamente in tutti i casi, per quanto posso dire, ma sembra proprio sul serio " un-OCaml "per me, soprattutto perché sto attraversando la lunghezza dell'int due volte con due funzioni interne. Quindi mi chiedo se c'è un modo più "OCaml" per farlo.

+0

Perché non int -> string -> char array -> inverso char array -> string -> reverse int? Non è OCaml, ma ho fatto cose simili in SML/NJ (usando implode ed esplodi che a OCaml sembra mancare) mentre gioco con https://en.wikipedia.org/wiki/Lychrel_number. Il concatenamento di trasformazioni semplici è abbastanza idiomatico nella programmazione funzionale. Potrebbe comportare più passaggi sui dati, ma "evitare l'ottimizzazione prematura" è un buon consiglio quando si impara una lingua. –

+4

Non vedo nulla di non convenzionale sulla tua soluzione. Ci sono probabilmente alcune soluzioni più intelligenti, ma questa è una domanda diversa. –

risposta

4

Direi che quanto segue è abbastanza idioma.

(* [rev x] returns such value [y] that its decimal representation 
    is a reverse of decimal representation of [x], e.g., 
    [rev 12345 = 54321] *) 
let rev n = 
    let rec loop acc n = 
    if n = 0 then acc 
    else loop (acc * 10 + n mod 10) (n/10) in 
    loop 0 n 

Ma, come ha detto Jeffrey in un commento, la soluzione è molto idiomatica, anche se non il più bello.

Btw, il mio stile, sarebbe quella di scrivere in questo modo:

let rev n = 
    let rec loop acc = function 
    | 0 -> acc 
    | n -> loop (acc * 10 + n mod 10) (n/10) in 
    loop 0 n 

come preferisco pattern matching a if/then/else. Ma questa è una questione di mio gusto personale.

+0

Grazie; questo era sulla falsariga di ciò che immaginavo. Per quanto riguarda le altre risposte, probabilmente avrei dovuto menzionare nel mio post che stavo cercando di evitare di usare funzioni "built-in" come string_of_int. –

1

posso proporvi qualche modo di farlo:

let decompose_int i = 
    let r = i/10 in 
    i - (r * 10) , r 

Questa funzione mi permette di scomporre il numero intero come se avessi una lista. Ad esempio 1234 è scomposto in 4 e 123. Quindi lo invertiamo.

let rec rev_int i = match decompose_int i with 
    | x , 0 -> 10 , x 
    | h , t -> 
    let (m,r) = rev_int t in 
    (10 * m, h * m + r) 

L'idea è quella di tornare 10, 100, 1000 ... e così via per sapere dove posizionare l'ultima cifra.


Quello che ho voluto fare qui è di trattarli come tratterei liste, decompose_int essere un List.hd e List.tl equivalente.