F# function composition changes base function types

102 views Asked by At

I'm working through this F# wikibook and I'm confused at something I'm seeing in the function composition section of the linked page.

The simplest example I can come up with follows:

// int -> int
let f x = x + x
// float -> float
let g x = x + 1.0

This is fine. I understand the types of these functions easily and I can run them in fsi and confirm that they take and return values of the types I've called out above.

If I add the following line, then I see the change I'm not so sure I understand.

// equivalent to f (g x)
let fog = f << g

The way I understand this, it shouldn't work because f expects an int, but g returns a float.

If I define this composition in fsi, I get the expected type error. If I put all these in a .fsx file and send the whole thing to fsi, the signature of f becomes float -> float.

I am confused as to the following:

  • scope of the type inference happening?
  • what is different between defining these in a file and in fsi?

I have tried searching, but I don't know enough at this point to effectively find answers to these questions. I'll be happy to RTFM if you can help point me to the parts that address these.

1

There are 1 answers

4
Gus On BEST ANSWER

The confusion comes from the fact that while the (+) operator is generic, it has a default type which is int so depending on the rest of the code you are compiling it will apply or not the default type.

This means that if you give type inference only this:

let f x = x + x

It will be inferred as int but it could have been any other numeric type that support the (+) operator, but since you gave no more information it uses the default.

Note that F# has to choose a type for this function in order to be encoded in .NET type systems, unless you define it inline, if you do so it will remain generic.

let inline f x = x + x

// val inline f :  x: ^a ->  ^b when  ^a : (static member ( + ) :  ^a *  ^a ->  ^b)

Now if you compile additional code along with that line, that uses the function f, type inference can analyze the types and get a more accurate candidate.

Here's a simpler example, open a new script and paste this code:

let f x = x + x
let v = f 1.

Now execute it line-by-line by pressing CTRL + ' at each line, it will infer int and will fail on the second line.

But now select the whole script and press ALT + ENTER, it will compile and f will be inferred with float since it was able to use the information of the following line which uses f.