2015-07-12 5 views
5

Я учу себя OCaml, а основные ресурсы, которые я использую для практики, - это некоторые проблемы, которые Cornell предоставил из своего класса 3110. Одна из проблем заключается в том, чтобы написать функцию для инвертирования int (i.e: 1234 -> 4321, -1234 -> -4321, 2 -> 2, -10 -> -1 и т. Д.).Реверсирование int в OCaml

У меня есть рабочее решение, но я обеспокоен тем, что это не совсем идиоматические 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 

Он работает должным образом во всех случаях, насколько я могу сказать, но это только кажется, серьезно " un-OCaml ", особенно потому, что я пробегаю длину int дважды с двумя внутренними функциями. Поэтому мне просто интересно, есть ли способ «OCaml» сделать это.

+0

Почему не int -> string -> char array -> reverse array array -> string -> reverseed int? Это не OCaml, но я делал аналогичные вещи в SML/NJ (используя implode и explode, которого, похоже, не хватает OCaml) во время игры с https://en.wikipedia.org/wiki/Lychrel_number. Объединение простых преобразований довольно идиоматично в функциональном программировании. Это может привести к нескольким проходам над данными, но «избегать преждевременной оптимизации» является хорошим советом при изучении языка. –

+4

Я не вижу ничего однообразного в вашем решении. Вероятно, есть несколько более умных решений, но это другой вопрос. –

ответ

4

Я бы сказал, что следующее достаточно идиоматично.

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

Но, как сказал Джеффри в комментарии, ваше решение вполне идиоматическое, хотя и не самый хороший один.

Btw, мой собственный стиль, было бы написать так:

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

Как я предпочитаю шаблон согласования с if/then/else. Но это вопрос моего личного вкуса.

+0

Thanks; это было похоже на то, что я себе представлял. Что касается других ответов, я, вероятно, должен был упомянуть в своем сообщении, что я пытался избежать использования встроенных функций, таких как string_of_int. –

1

Я могу предложить вам несколько способов сделать это:

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

Эта функция позволяет мне разложить целое число, как если бы у меня был список. Например, 1234 разлагается на 4 и 123. Затем мы отменим его.

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) 

Идея заключается в том, чтобы вернуть 10, 100, 1000 ... и так далее, чтобы знать, куда поместить последнюю цифру.


То, что я хотел сделать здесь, чтобы рассматривать их как я бы рассматривать списки, decompose_int быть List.hd и List.tl эквивалент.

Смежные вопросы