【问题标题】:SML - Incrementing a value in a tuple during foldl that needs to be returnedSML - 在 foldl 期间增加需要返回的元组中的值
【发布时间】:2023-03-28 06:18:01
【问题描述】:

我在尝试在内部 foldl 调用中增加 x 的值时遇到问题。我使 x 等于传入的 shiftValue 并尝试在内部 foldl 调用中找到 #" " 或 #"*" 时增加它,但是返回的 x 的值始终与传入时的 shiftvalue 相同.

该函数接受一个 (string, int) 元组,其中字符串将在任何其他字符之前有前导空格和星号被切掉。此外,末尾没有任何其他字符的任何空格或星号都将被切掉。传入的 int 是一个 shiftValue,它跟踪字符串在传递到此函数之前已移动了多少个空格。每当我去掉前导空格或星号时,我都需要将 shiftValue "x" 加一。

内部 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); (* 应该打印出 ("hello", 6) *) 但打印出("hello", 3)

【问题讨论】:

    标签: tuples sml smlnj fold


    【解决方案1】:

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

    val x = shiftValue
    

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

    x = x + 1
    

    请记住,在 SML 中,您不能更改变量的值(实际上,出于这个原因,它们在 SML 中只是称为值)。 x = x + 1 只是比较xx + 1,所以语句x = x + 1 的值是布尔值false

    【讨论】:

    • 我不知道你不能改变这个值。谢谢!我摆脱了 x = x + 1 并制作了一个单独的函数来处理更改 shiftValue。
    • Re:“实际上,它们在 SML 中只是称为值”:根据标准 ML 的定义(修订版)x 是一个“值变量”。 (它也是一个“值标识符”和“长值标识符”,等等。)不可变变量不会是“变量”的概念是错误的;只是标准 ML 中的变量更像数学中的变量,而不是许多其他语言中的变量。
    【解决方案2】:

    正如 Tayacan 所说,变量在 SML 中是不可变的。如果您想要可变性,则需要使用引用类型——但通常最好避免使用它们,最好坚持使用函数式样式。

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

    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
    

    【讨论】:

    • 它不会删除中间的星星,我不关心效率,但感谢您的替代建议。
    • 此外,如果我从前面移除星号,则 shiftValue 会发生变化,但当它们从后面移除时不会发生变化,这就是为什么我无法比较之后的新字符串长度。
    • 啊,对不起,中间的星星你说得对,我看错了代码。重新转换:我明白了,但是为什么将其设为 参数?我用返回班次计数的版本更新了答案。
    猜你喜欢
    • 2012-04-01
    • 2013-01-17
    • 1970-01-01
    • 1970-01-01
    • 2022-08-18
    • 1970-01-01
    • 1970-01-01
    • 2014-11-18
    • 2019-03-07
    相关资源
    最近更新 更多