Search code examples
sml

Does this "count" is a mutation?


fun count_wcs p =
    let
        val count = 0
    in
        g (fn () => count + 1) (fn y => 1) p
    end

I'm doing homework and we're not supposed to use mutations, this doesn't reassign the value to anything but it doesn't feel right. Please, don't say what is the right way to do this, because I'm supposed to figure this out.

datatype pattern = Wildcard
         | Variable of string
         | UnitP
         | ConstP of int
         | TupleP of pattern list
         | ConstructorP of string * pattern

fun g f1 f2 p =
    let
    val r = g f1 f2
    in
    case p of
        Wildcard          => f1 ()
      | Variable x        => f2 x
      | TupleP ps         => List.foldl (fn (p,i) => (r p) + i) 0 ps
      | ConstructorP(_,p) => r p
      | _                 => 0
    end

This function g has to receive a type unit -> int function as the first argument. I checked the count after I called the function and got 0, so it is ok to write it like this, right? But still, it does feel sloppy.

Added the context (function g and the datatype used). The function count_wcs is supposed to count the number a Wildcard pattern appears in a pattern.


Solution

  • This does not count as a mutation, but it does resemble what you might do if you had them and is probably not going to work, depending on what it is you're doing. Mutations require references and they're made with ref and are de-referenced with !. So just stick away from those. :-)

    You're doing something that will be of little benefit:

    let
      val count = 0
    in
      ...
    end
    

    will bind count to 0, but will never cause count to have any other value; I presume that you want to eventually have that count increases. If it had been a reference, val count = ref 0, you could increment it by doing count := !count + 1, but since it's not, you have to make count a variable of some function for it to change.

    For example:

    fun count_4s ([],    count) = count
      | count_4s (x::xs, count) = count_4s (xs, if x = 4 then count + 1 else count)
    

    In each call count is constant, but in each subsequent, recursive call it is possibly incremented.

    This function g has to receive a type unit -> int function as first argument.

    ...
    g (fn () => count + 1) (fn y => 1) p
    ...
    

    [...] But still it does feel sloppy.

    Assuming that g's first arguments have no side-effects and do not throw exceptions and do not loop forever, all they can do is return the same thing on every call. This makes them rather boring. Typically functions that either take as input or return () : unit do something else, like read or write from a source external to the program.

    I wouldn't call it sloppy. Just a bit weird, without knowing the context.