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