Question

I'm having a problem while trying to increment my value of x inside the inner foldl call. I make x equal to shiftValue that's passed in and attempt to increment it whenever I find a #" " or #"*" in the inner foldl call, but the value of x that gets returned is always the same as shiftvalue was when passed in.

The function takes in a tuple of (string, int) where the string will have leading spaces and asterisk chopped off that come before any other characters. Also any spaces or asterisk on the end not followed by any other characters will get chopped off. The int that is passed in is a shiftValue that tracks how many spaces the string was shifted over before getting passed into this function. Whenever I take off a leading space or asterisk I need to increment the shiftValue "x" by one.

The inner foldl call removes asterisks and spaces from the front. The outer foldl call removes them from the back. The asterisks and spaces get removed right, the x value just isn't getting updated.

(*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); (* Should print out ("hello", 6) *) but prints out ("hello", 3)

Was it helpful?

Solution

Look at your x - in the beginning of your function, you do:

val x = shiftValue

Then, later, you try to do this:

x = x + 1

Remember, in SML, you can't change the value of a variable (actually, they're just called values in SML, for that reason). x = x + 1 just compares x and x + 1, so the value of the statement x = x + 1 is boolean false.

OTHER TIPS

As Tayacan says, variables are not mutable in SML. If you want mutability you need to use reference types -- but usually, they are best avoided and it's preferable to stick to functional style.

It's also worth noting that your function is going to be very inefficient (O(n^2)), because of your use of list concatenation and length on every iteration. And it is incorrect, because it will also remove stars in the middle of the string (and then redundantly go over the whole list a second time). Finally, your solution is far too complicated.

FWIW, here is the shortest implementation I can think of, using the Substring library module and the function composition operator o:

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

This does not use your shiftValue because I don't understand what it's supposed to do. You can easily compute the number of removed characters by comparing the old and new string size. That is, your intended function (IIUC) could easily be expressed on top of mine as

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

But to be honest, I don't understand what this version would be good for.

Edit: A version that returns the left drop count:

fun trimStars s =
    let
        open Substring
        val ss = dropl isStarOrSpace (dropr isStarOrSpace (full s))
    in
        (string ss, #2(base ss))
    end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top