我有以下公式
fun foo 0 = [0]
| foo num = let val l = (num mod 2)::foo(num div 2) in
rev l
end;
应该从十进制转换为二进制。它具有以下签名
val foo = fn : int -> int list
我不确定我在哪里弄错了,因为我得到的结果不正确。可能有人帮我弄清楚我在哪里犯了错误?
答案 0 :(得分:3)
问题似乎是你在每个递归步骤中反转结果列表,而不是在结束时反转一次。
此外,您可能需要将0映射到空列表,否则最终会有一个0太多。
答案 1 :(得分:3)
正是安德烈亚斯所说的。现在,解决这个问题的显而易见的方法是使用包装函数:
fun f n =
let
fun f' 0 = []
| f' num = num mod 2 :: f' (num div 2)
in
rev (f' n)
end
这样可行,但缺点是首先构建列表,然后遍历它(rev
调用)。它也不是尾递归的。我们可以做得更好!
我们不是使用反向,而是使用累加器:
fun g n =
let
fun g' 0 acc = acc
| g' num acc = g' (num div 2) (num mod 2 :: acc)
in
g' n []
end
为了理解差异,让我们看看如果我们在数字4上运行每一个会发生什么。
f 4 -> rev (f' 4)
-> rev (4 mod 2 :: f' (4 div 2))
-> rev (0 :: f' 2)
-> rev (0 :: 2 mod 2 :: f' (2 div 2))
-> rev (0 :: 0 :: f' 1)
-> rev (0 :: 0 :: 1 mod 2 :: f' (1 div 2))
-> rev (0 :: 0 :: 1 :: f' 0)
-> rev (0 :: 0 :: 1 :: [])
-> [1, 0, 0]
g 4 -> g' 4 []
-> g' (4 div 2) (4 mod 2 :: [])
-> g' 2 (0 :: [])
-> g' (2 div 2) (2 mod 2 :: 0 :: [])
-> g' 1 (0 :: 0 :: [])
-> g' (1 div 2) (1 mod 2 :: 0 :: 0 :: [])
-> g' 0 (1 :: 0 :: 0 :: [])
-> [1, 0, 0]