2013-11-28 50 views
0

假设我们使用一个列表来反向表示数字,每个节点都是数字中的一个数字。在OCaml中添加两个列表

所以[1;2;3;4;5]是数54321

现在我们要添加了两个这样的列表,例如,添加[1; 2]和[3; 4],我们得到[4; 6],这是数64


这里是我的代码:

let add l1 l2 = 
    let rec add_to up acc = function 
    | [] -> if up = 1 then 1::acc else acc 
    | hd::tl -> 
     let s = hd+up in 
     if s >= 10 then add_to 1 ((s-10)::acc) tl 
     else List.rev_append tl (s::acc) 
    and 
    add_up up acc = function 
    | [], [] -> if up = 1 then 1::acc else acc 
    | l, [] | [], l -> (add_to up [] l) @ acc 
    | hd1::tl1, hd2::tl2 -> 
     let s = hd1+hd2+up in 
     if s >= 10 then add_up 1 ((s-10)::acc) (tl1, tl2) 
     else add_up 0 (s::acc) (tl1, tl2) 
    in 
    List.rev (add_up 0 [] (l1, l2)) 

的想法很简单,只是从两个列表添加两个HDS,并携带1到下一如果两个HDS的总和是更大或相等与10.

但是,我认为我的代码看起来不漂亮。

  1. 我们有解决进位的逻辑的冗余部分。
  2. 我必须在两个列表上做@

任何人都可以帮助我使它更美丽?

回答

1

我认为诀窍是推广。本质是增加三件事,而不是两件。

let sum a b = 
    let rec isum a b c = 
     match a, b with 
     | [], [] -> if c = 0 then [] else [c] 
     | [], x | x, [] -> isum [0] x c 
     | ah :: at, bh :: bt -> 
      let s = ah + bh + c in 
      (s mod 10) :: isum at bt (s/10) 
    in 
    isum a b 0 

此代码不是尾递归。尾递归版本会稍微不太优雅。

注:我假设你使用[]来表示0

+0

漂亮的代码,真好看。我没有想到处理单个列表实际上是处理两个列表与另一个是0 –

+0

可以请你看看http://stackoverflow.com/questions/20332184/round-robin-algorithm-in-ocaml –