我相信我正在将我的第一个函数转换为仅使用赋值和循环。我知道这是针对函数式编程的,但这是教授想要的。
递归函数:
fun sub (x, y, []) = []
| sub (x, y, z::zz) = if x = z then y::sub(x, y, zz)
else z::sub(x, y, zz);
迭代翻译:
fun sub2 (x, y, z) =
let val ret = ref []; val temp = z;
in
while !temp <> []
do (if x = hd(!temp) then ret := !ret::y; temp := tl(!temp)
else ret := ret::hd(!temp); temp := tl(!temp));
!ret;
end;
我在smlnj上运行以下错误。第一个是do,第二个是结束。
错误:语法错误:用EQUALOP替换END
错误:在EOF中找到语法错误
我很感激帮助调试或者更简洁的方法来完成这个迭代功能。
答案 0 :(得分:4)
为什么哦,为什么他不会那样?没关系......
有很多问题。
!temp <> null
将会受到限制。使用List.null函数代替“最佳实践”。!ret;
的分号不应该在您的序列停止时出现,否则end
将成为失败的序列的一部分。ret
。'a * 'a list
,因此获取元素,然后是元素列表。解决这个问题并保持元素顺序的一种方法是使用append(@)函数,然后将元素放在单个列表中。然而,有更多的方法以更好的方式处理它,因为追加函数在大列表上的表现非常糟糕。以下是一个有效的功能:
fun sub2 (x, y, z) =
let
val ret = ref []
val temp = ref z
in
while not (null (!temp)) do
if x = hd(!temp) then
(ret := !ret @ [y];
temp := tl(!temp))
else
(ret := !ret @ [hd(!temp)];
temp := tl (!temp));
!ret
end
这里可以改进的一个显而易见的事情是你总是用相同的值更新temp。所以这可以被考虑在内。而且条件可以改为案例
fun sub2 (x, y, z) =
let
val ret = ref []
val temp = ref z
in
while not (null (!temp)) do
(case x = hd(!temp) of
true => ret := y :: !ret
| false => ret := hd(!temp) :: !ret
;temp := tl (!temp));
rev (!ret)
end
特别注意元素不是如何附加到结果列表中,而是放在前面然后在结尾处反转生成的列表以获得正确的顺序。这将使您在大型列表上获得更好的性能。然而,当你在SML中使用命令式样式时,仍然有更好的方法。
正如您已经看到的,它可以以功能的方式完成。但它也可以更简单。请考虑以下使用地图。
fun sub3 (x, y, zs) = map (fn z => if z = x then y else z) zs