views:

719

answers:

5
+1  Q: 

Loops in SML/NJ

I'm very new to SNL/NJ and was wondering how I could accomplish the following:

foo(stuff,counter)
{
   while(counter > 0)
   {
     bar(stuff);
     counter-1;
   }
   return;
}

Something like this, but how do I decrement?:

foo(stuff,counter) = 
   while counter > 0 do bar(stuff) ??? // how do I decrement counter here?
+3  A: 

In a functional program, a mutable variable turns into a parameter, typically to a nested helper function.

Since in your example, the thing being mutated is aleady parameter, no helper function is needed. Your code becomes

fun foo stuff counter =
  if counter > 0 then
    ( bar stuff
    ; foo stuff (counter-1)
    )
  else
    ()

Of course this code is still terribly imperative... The call bar stuff is executed purely for side effect. Not very ML-ish.

Norman Ramsey
+1 for the ; indentation !
You can call me Chuck
+1  A: 

Short answer: You don't. In functional programming, you generally never modify variables, which means a loop is impossible. Instead, you can implement the same using recursion. Similarly, since you don't, generally speaking, have side effects, function calls only make sense if they return data. So bar(stuff) is probably not very useful. It has no way of affecting the rest of the application. In a functional programming style, your bar() function should be called on different data each time, and return something that the rest of the application can act on.

(ML does allow side effects in certain cases, but to keep things simple, let's ignore that for now)

What exactly are you trying to achieve? (What do you need to loop over, what do the functions do?

If you provide a bit more detail, we can explain more specifically how you should write the program. But as it is, your program simply doesn't make sense in a functional style.

jalf
+2  A: 

I agree with the other contributors that you should generally use recursion instead of loops and mutation to do this in a functional language.

If you really wanted to use mutation and loops though, you would need to use a data structure called a reference which is a kind of "mutable cell". You allocate the reference with the ref function, passing it the initial contents. You access the contents using the ! operator. And you set new contents using the := operator. So the literal translation of your code above would be something like the following. As you can see, the syntax is really ugly and that is another reason why people avoid it.

fun foo (stuff, counter_start) =
let
  val counter = ref counter_start
in
  while !counter > 0 do (
    bar stuff;
    counter := !counter - 1
  )
end;
newacct
+1  A: 

I don't know ML, but this is some ML-like pseudo code:

fun foo stuff 0 = return ()
  | foo stuff counter = (bar stuff; foo stuff (counter - 1))

I don't know how to "chain" commands in ML; the semicolon is just a placeholder.

Generally, you wouldn't loop. I would rather expect the usual higher order functions. When you get used to those, manually writing a loop will feel like coding assembler.

edit: fixed code according to comment

Svante
That's pretty much right, except you need to enclose the chained commands in parentheses because the semicolon has lower precedence than the function definition.Also, I think the OP wanted the action to be performed 0 times when the counter is 0, so in the first case, you would probably not do "bar stuff"; and instead just return "()" (unit).
newacct
A: 

Great, thanks for all the help!