Reputation: 2562
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)
Upvotes: 0
Views: 1589
Reputation: 36118
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
Upvotes: 1
Reputation: 1826
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
.
Upvotes: 3