I'm trying to learn smlnj at the moment and am having trouble with a fold function.
What I'm trying to do is write a function, select, that uses the folding pattern and takes in a function and a list. It will take the head of the list into the function to determine whether it will add that element to the list. Here is an example of what I mean.
select (fn x => x mod 2 = 0) [1,2,3,4,5,6,7,8,9,10];
val it = [2,4,6,8,10] : int list
So, here is what I have so far...
fun select f l = foldl (fn (x,y) => if (f(x)) then x else 0) 0 l;
This obviously doesn't work correctly. It simply returns 10. I'm sure I need to use op:: somehow to get this to work, but I can't figure it out. My thought is that it should look something like this...
fun select f l = foldl (fn (x,y) => if (f(x)) then op:: else []) [] l;
But this does not work. Any help would be appreciated. Thanks!
You're close. The only problems are the if
/else
cases in the function you're passing to fold
.
Remember, in your fn (x,y)
, x
is the list element you're considering, and y
is the result of folding the rest of the list. If f(x)
fails, then you want to exclude x
from the result, so you just pass y
along. If f(x)
succeeds, you want to include x
in your result, so you return y@[x]
.
Note that it's best to avoid using the append operator (y@[x]
) where you can, as it's a linear-time operation, while prepending (x::y
) is constant. Of course, substituting one for the other in this case will construct your list backwards. You can get around this by folding backwards as well, i.e. using foldr
instead of foldl
.