SML Warning: Type Vars Not Generalized when using Empty Lists or NONE option

后端 未结 1 1640
無奈伤痛
無奈伤痛 2021-01-11 15:10

I can\'t for the life of me figure out why the following SML function is throwing a Warning in my homework problem:

fun my_func f ls  = 
  case ls of 
  []          


        
相关标签:
1条回答
  • 2021-01-11 15:45

    The value restriction referenced in the warning is one of the trickier things to understand in SML, however I will do my best to explain why it comes up in this case and try to point you towards a few resources to learn more.

    As you know, SML will use type inference to deduce most of the types in your programs. In this program, the type of my_func will be inferred to be ('a -> 'b option) -> 'a list -> 'b. As you noted, it's a polymorphic type. When you call my_func like this

    myfunc f [NONE, SOME 1, NONE];
    

    ... the type variables 'a and 'b are instantiated to int option and int.

    However when you call it without a value such as SOME 1 above

    myfunc f [NONE, NONE];
    

    What do you think the type variables should be instantiated to? The types should be polymorphic -- something like 't option and 't for all types 't. However, there is a limitation which prevents values like this to take on polymorphic types.

    SML defines some expressions as non-expansive values and only these values may take on polymorphic types. They are:

    • literals (constants)
    • variables
    • function expressions
    • constructors (except for ref) applied to non-expansive values
    • a non-expansive values with a type annotation
    • tuples where each field is a non-expansive value
    • records where each field is a non-expansive value
    • lists where each field is a non-expansive value

    All other expressions, notably function calls (which is what the call to my_func is) cannot be polymorphic. Neither can references. You might be curious to see that the following does not raise a warning:

     fn () => my_func f [NONE, NONE];
    

    Instead, the type inferred is unit -> 'a. If you were to call this function however, you would get the warning again.

    My understanding of the reason for this restriction is a little weak, but I believe that the underlying root issue is mutable references. Here's an example I've taken from the MLton site linked below:

    val r: 'a option ref = ref NONE
    val r1: string option ref = r
    val r2: int option ref = r
    val () = r1 := SOME "foo"
    val v: int = valOf (!r2)
    

    This program does not typecheck under SML, due to the value restriction. Were it not for the value restriction, this program would have a type error at runtime.

    As I said, my understanding is shaky. However I hope I've shed a little light on the issue you've run into, although I believe that in your case you could safely ignore the warning. Here are some references should you decide you'd like to dig deeper:

    http://users.cis.fiu.edu/~smithg/cop4555/valrestr.html

    http://mlton.org/ValueRestriction

    (BTW the MLton site is solid gold. There's so much hidden away here, so if you're trying to understand something weird about SML, I highly recommend searching here because you'll likely turn up a lot more than you initially wanted)

    Since it seems like you're actually using SML/NJ, this is a pretty handy guide to the error messages and warnings that it will give you at compile time:

    http://flint.cs.yale.edu/cs421/smlnj/doc/errors.html

    0 讨论(0)
提交回复
热议问题