Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reversing an int in OCaml

I'm teaching myself OCaml, and the main resources I'm using for practice are some problem sets Cornell has made available from their 3110 class. One of the problems is to write a function to reverse an int (i.e: 1234 -> 4321, -1234 -> -4321, 2 -> 2, -10 -> -1 etc).

I have a working solution, but I'm concerned that it isn't exactly idiomatic 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

It works properly in all cases as far as I can tell, but it just seems seriously "un-OCaml" to me, particularly because I'm running through the length of the int twice with two inner-functions. So I'm just wondering whether there's a more "OCaml" way to do this.

like image 246
Chirayu Poudel Avatar asked Jul 12 '15 16:07

Chirayu Poudel


2 Answers

I would say, that the following is idiomatic enough.

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

But as Jeffrey said in a comment, your solution is quite idiomatic, although not the nicest one.

Btw, my own style, would be to write like this:

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

As I prefer pattern matching to if/then/else. But this is a matter of mine personal taste.

like image 126
ivg Avatar answered Nov 09 '22 02:11

ivg


I can propose you some way of doing it:

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

This function allows me to decompose the integer as if I had a list. For instance 1234 is decomposed into 4 and 123. Then we reverse it.

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)

The idea here is to return 10, 100, 1000... and so on to know where to place the last digit.


What I wanted to do here is to treat them as I would treat lists, decompose_int being a List.hd and List.tl equivalent.

like image 30
Théo Winterhalter Avatar answered Nov 09 '22 01:11

Théo Winterhalter