Search code examples
f#smlsmlnj

Binding not exhaustive warning in SML/NJ but not in F# for same pattern


The SML/NJ code below results in a binding not exhaustive warning for "val Grove(whatTree) = glen". The F# equivalent code produces no warning. Why?

Standard ML of New Jersey (32-bit) v110.99.2 [built: Tue Sep 28 13:04:14 2021]:

datatype tree = Oak|Elem|Maple|Spruce|Fir|Pine|Willow
datatype vegetable = Carrot|Zucchini|Tomato|Cucumber|Lettuce
datatype grain = Wheat|Oat|Barley|Maize
datatype plot = Grove of tree|Garden of vegetable|Field of grain|Vacant
val glen = Grove(Oak)
val Grove(whatTree) = glen

F# 6.0.0 Warning Level 5:

type Tree = Oak|Elem|Maple|Spruce|Fir|Pine|Willow
type Vegetable = Carrot|Zucchini|Tomato|Cucumber|Lettuce
type Grain = Wheat|Oat|Barley|Maize
type Plot = Grove of Tree|Garden of Vegetable|Field of Grain|Vacant
let glen = Grove(Oak)
let Grove(whatTree) = glen

Why binding not exhaustive? The accepted answer to this related question gives me some hints about my question. The SML warning is indicating redundant code. So, I'll assume the F# compiler writers did not deem this case worthy of a warning.


Solution

  • This F# code let Grove(whatTree) = glen is ambiguous because it can be interpreted as value binding with deconstruction or function.

    In first case syntax is

    let pattern = expr
    

    In seconds case syntax is

    let name pattern-list = expr
    

    Since F# supports shadowing, it's legal to create new function. But SML seems to have different opinion on this and decides to bind value.

    In the end: code in SML and F# does different things, that's why there's no warnings


    To actually perform binding, left side of let should parenthesized:

    let (Grove(whatTree)) = glen
    

    It produces warning: C:\stdin(6,5): warning FS0025: Incomplete pattern matches on this expression. For example, the value 'Field (_)' may indicate a case not covered by the pattern(s).