For in Standard ML

Standard ML (SML) doesn’t have a built-in looping construct like for. Instead, we typically use recursion or higher-order functions to achieve similar results. Here are some examples of how we can replicate the Go for loop behavior in SML:

(* The most basic type, with a single condition. *)
fun loop1 i =
    if i <= 3 then
        (print (Int.toString i ^ "\n");
         loop1 (i + 1))
    else ();

(* A classic initial/condition/after loop. *)
fun loop2 j =
    if j < 3 then
        (print (Int.toString j ^ "\n");
         loop2 (j + 1))
    else ();

(* Another way of accomplishing the basic "do this N times" iteration *)
fun loop3 n =
    if n > 0 then
        (print ("range " ^ Int.toString (3 - n) ^ "\n");
         loop3 (n - 1))
    else ();

(* A loop that continues until a break condition *)
fun loop4 () =
    (print "loop\n";
     (* In SML, we don't have a break statement, so we just return *)
     ());

(* A loop with continue-like behavior *)
fun loop5 n =
    if n < 6 then
        (if n mod 2 <> 0 then
            print (Int.toString n ^ "\n")
        else ();
         loop5 (n + 1))
    else ();

(* Main function to run all the loops *)
fun main () =
    (loop1 1;
     loop2 0;
     loop3 3;
     loop4 ();
     loop5 0)

(* Run the main function *)
val _ = main ()

To run this program, you would typically save it in a file (e.g., loops.sml) and then use an SML interpreter or compiler. For example, with Standard ML of New Jersey (SML/NJ):

$ sml loops.sml
1
2
3
0
1
2
range 0
range 1
range 2
loop
1
3
5

In Standard ML, we use recursion to implement loop-like behavior. Each function calls itself with updated parameters until a base condition is met. This is the idiomatic way to express iteration in functional programming languages like SML.

The range-like functionality is simulated by passing a counter that decrements, and the “continue” behavior is achieved by using an if-else statement to skip the print for even numbers.

Note that Standard ML doesn’t have mutable variables in the same way as imperative languages, so we pass and return updated values instead of modifying variables in place.

This example demonstrates how to translate imperative loop constructs into functional programming patterns, which is a common task when moving between these different programming paradigms.