Search code examples
f#type-inferenceunit-type

F# inferred types in If/Then


If I have the following function:

let myFunc x y =
  if y = 0 then 1
  x

I get the error:

Program.fs(58,17): error FS0001: This expression was expected to have type
    unit    
but here has type
    int    

Why does the compiler expect 'unit' instead of int ?


Solution

  • It might worth adding that this is not just a property of if. F# is an expression-based language meaning that pretty much every piece of code (aside from type declarations and a few exceptions) is an expression that evaluates to some result. In fact, F# does not call if the if statement, but an if expression.

    This means that you can use if in unexpected places. For example, this might be useful:

    x/2 + (if x%2=0 then 0 else 1) 
    

    As already explained by Garry, if you omit else, then the expression still needs to return something - if the result was to be an int, then it would not really make sense (which number should the compiler pick?), so it requires that the result is of type unit, which is a special type representing "no result".

    The unit type is also the result of all imperative functions (e.g. printf) or of all expressions that do not logically return any value (assignment or e.g. loop). This means that if you write:

    if x > 0 then printfn "Big!"
    

    ... then the expression is well-typed, because printfn "Big!" has a return type unit and the implicitly added else branch also returns unit. You can create a value of type unit directly by hand (the type has exactly one value), so the above actually corresponds to:

    if x > 0 then printfn "Big!" else ()
    

    From the C# perspective, it makes more sense to read if .. then .. else as the conditional operator:

    x/2 + (x%2 == 0 ? 0 : 1)