SML中十进制到二进制的转换
我有下面的公式SML中十进制到二进制的转换,sml,smlnj,Sml,Smlnj,我有下面的公式 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 我不确定我到底在哪里出错,因为我得到的结果不正确。有人能帮我找出我在哪里出错吗?问题似乎是,在每个递归步骤中都要反转结果列表,而不是在最后只反转一次 此外
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映射到空列表,否则最终将有一个0过多。正是Andreas所说的。现在,解决这个问题的明显方法是使用包装器函数:
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]
我最终得到了它,在所有的转换之后,我反转了
local-fun-convert 0=[0]| convert x=如果x=1,那么[1]else(Int.rem(x,2))::convert(x div 2)in-fun-foo num=rev(convert(num))end代码>