SML - 在需要返回的foldl期间递增元组中的值

时间:2013-06-30 01:37:43

标签: tuples sml smlnj fold

我在尝试增加内部foldl调用中的x值时出现问题。我使x等于传入的shiftValue并尝试在内部foldl调用中找到#“”或#“*”时递增它,但返回的x的值总是与传入时的shiftvalue相同

该函数接受(string,int)元组,其中字符串将具有前导空格,并且在任何其他字符之前切断星号。此外,任何空格或星号后面没有任何其他字符将被切断。传入的int是一个shiftValue,它跟踪字符串在传递给此函数之前移位了多少空格。每当我取下前导空格或星号时,我需要将shiftValue“x”加1。

内部foldl调用从前面删除星号和空格。外部foldl调用将它们从背面移除。右边的星号和空格被删除,x值没有得到更新。

(*Take string str and get rid of leading and following #"*"s and #" "s. For every 
leading #"*" or #" " removed increment the shiftValue returned in the tuple*)

fun trimStarsOnNode (str, shiftValue) =
    let 
        val x = shiftValue
    in
        ((implode(rev (foldl (fn (cur, a) => 
            if length a = 0 andalso cur = #"*" then a @ []
            else
                if length a = 0 andalso cur = #" " then a @ []
                else a @ [cur]) []  (rev (foldl (fn (cur, a) => 
                    if length a = 0 andalso cur = #"*" then (x = x + 1; a @ [])
                    else
                        if length a = 0 andalso cur = #" " then (x = x + 1; a @ [])
                        else a @ [cur]) [] (explode str)))))), x)
    end;

trimStarsOnNode ("***hello", 3);(*应打印出来(“你好”,6)*)但打印出("hello", 3)

2 个答案:

答案 0 :(得分:3)

看看你的x - 在你的函数的开头,你做:

val x = shiftValue

然后,您稍后尝试这样做:

x = x + 1

请记住,在SML中,您无法更改变量的值(实际上,由于这个原因,它们只是在SML中调用了值)。 x = x + 1仅比较xx + 1,因此语句x = x + 1的值为布尔值false

答案 1 :(得分:1)

正如Tayacan所说,变量在SML中是不可变的。如果你想要可变性,你需要使用引用类型 - 但通常,最好避免它们,并且最好坚持功能风格。

值得注意的是,由于您在每次迭代时都使用了列表并置和length,因此您的函数效率非常低(O(n ^ 2))。 这是不正确的,因为它也会删除字符串中间的星号(然后再次冗余地遍历整个列表)。最后,你的解决方案太复杂了。

FWIW,这是我能想到的最短的实现,使用Substring库模块和函数组合运算符o

fun isStarOrSpace c = (c = #"*" orelse c = #" ")
val trimStars =
    let open Substring
    in string o dropl isStarOrSpace o dropr isStarOrSpace o full end

这不会使用你的shiftValue,因为我不明白它应该做什么。您可以通过比较新旧字符串大小轻松计算删除的字符数。也就是说,您的预期功能(IIUC)可以很容易地在我的上面表达

fun trimStarsOnNode(s, shift) =
    let val s' = trimStars s in (s', size s - size s' + shift) end

但说实话,我不明白这个版本会有什么好处。

修改:返回左下降计数的版本:

fun trimStars s =
    let
        open Substring
        val ss = dropl isStarOrSpace (dropr isStarOrSpace (full s))
    in
        (string ss, #2(base ss))
    end