2015-07-12 13 views
5

Ich unterrichte mich OCaml, und die Hauptressourcen, die ich für die Praxis verwende, sind einige Problemsätze, die Cornell von ihrer Klasse 3110 zur Verfügung gestellt hat. Eines der Probleme besteht darin, eine Funktion zu schreiben, um ein int umzukehren (d. H .: 1234 -> 4321, -1234 -> -4321, 2 -> 2, -10 -> -1 etc.).Ein int in OCaml umkehren

Ich habe eine funktionierende Lösung, aber ich bin besorgt darüber, dass es nicht gerade idiomatisch OCaml ist:

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 

Es funktioniert in allen Fällen, soweit ich das beurteilen kann, aber es scheint nur ernst " un-OCaml "für mich, vor allem, weil ich zweimal mit zwei inneren Funktionen durch die Länge des int renne. Ich frage mich nur, ob es einen "OCaml" Weg gibt, dies zu tun.

+0

Warum nicht int -> string -> char-array -> umgekehrtes char-array -> string -> reversed int? Es ist nicht OCaml, aber ich habe ähnliche Sachen in SML/NJ gemacht (mit implode und explode, was OCaml zu fehlen scheint), während ich mit https://en.wikipedia.org/wiki/Lychrel_number herumspiele. Das Verketten einfacher Transformationen ist in der funktionalen Programmierung ziemlich idiomatisch. Es kann mehrere Durchläufe über die Daten beinhalten, aber "vorzeitige Optimierung vermeiden" ist ein guter Ratschlag beim Erlernen einer Sprache. –

+4

Ich sehe nichts Unordentliches über Ihre Lösung. Es gibt wahrscheinlich einige cleverere Lösungen, aber das ist eine andere Frage. –

Antwort

4

Ich würde sagen, dass das folgende idiomatische genug ist.

(* [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 

Aber wie Jeffrey in einem Kommentar sagte, ist die Lösung ganz idiomatischen, wenn auch nicht der schönste.

Btw, mein eigener Stil, wäre wie folgt zu schreiben:

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

Als ich Muster if/then/else passend bevorzugen. Aber das ist eine Frage meines persönlichen Geschmacks.

+0

Danke; Dies entsprach meinen Vorstellungen. Was die anderen Antworten anbelangt, hätte ich wahrscheinlich in meinem Beitrag erwähnt, dass ich versuche, "eingebaute" Funktionen wie string_of_int zu vermeiden. –

1

kann ich Ihnen einen Weg, es zu tun vorschlagen:

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

Mit dieser Funktion können Sie mir die ganze Zahl zersetzen, als ob ich eine Liste hatte. Zum Beispiel wird 1234 in 4 und 123 zerlegt. Dann kehren wir es um.

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) 

Die Idee hier ist 10 zurückzukehren, 100, 1000 ... und so weiter zu wissen, wo die letzte Ziffer zu platzieren.


Was ich hier tun wollte, ist, sie zu behandeln, wie ich Listen behandeln würde, decompose_int ein Äquivalent List.hd und List.tl zu sein.