Search code examples
pattern-matchingsmlfifosmlnj

Pattern-match empty Fifo.fifo in SML/NJ


When I try to write something like

fun test Fifo.empty = true
  | test _ = false`

I get an error message that says Error: variable found where constructor is required: Fifo.empty. I'm really new to SML/NJ. Turns out it has something to do with Fifo.empty being a longId, but I haven't figured out how to fix this, except by patching it by passing the Fifo.isEmpty as an argument, but that's hardly a solution...


Solution

  • When you inspect the Fifo module,

    - open Fifo;
    [autoloading]
    [library $SMLNJ-LIB/Util/smlnj-lib.cm is stable]
    [autoloading done]
    opening Fifo
      datatype 'a fifo = ...
      exception Dequeue
      val empty : 'a fifo
      (* and so on *)
    

    you can see that Fifo.empty is an 'a fifo value. To see how it's made,

    - Fifo.empty;
    val it = Q {front=[],rear=[]} : 'a fifo
    

    Unfortunately the Q datatype constructor of 'a fifo is hidden by the module being opaque (so the datatype definition appears as "...". When you define a datatype, its constructors (e.g. Q) become both value constructors and pattern constructors, but when you declare values like Fifo.empty using such value constructors, they don't also become pattern constructors.

    I haven't figured out how to fix this, except by patching it by passing the Fifo.isEmpty as an argument, but that's hardly a solution...

    I'm not sure why you would need to pass in Fifo.isEmpty as an argument; can't you just refer to Fifo.isEmpty in the function body? Perhaps there are dimensions to this problem you're not explaining.

    How about the following:

    fun test queue = Fifo.isEmpty queue
    

    Or simply:

    val test = Fifo.isEmpty
    

    Generally, if you feel like passing in a bunch of library functions as arguments, you could instead consider building a higher-order module (functor) that takes another module as argument.