Why does F# function return a signature of "val FunctionName: int -> int"?

531 views Asked by At

I was following some examples on F# Wikibook on High Order Functions.

Second code snippet under title, Composition Function has following code snippet.

#light
open System

let compose f g x = f (g x)

let xSquared x = x*x
let negXPlusFive x = -x/2.0 + 5.0

let fog = compose xSquared negXPlusFive

// ... Console.WriteLine statements....

The one I am having problem understanding is

let xSquared x = x*x

When I run it with F# interactive shell (fsi.exe) by itself, I get the following signature.

> let xSquared x = x*x;;

val xSquared : int -> int

But when I run the whole code snippet, xSquared returns the following.

val compose : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b
val xSquared : float -> float
val negXPlusFive : float -> float
val fog : (float -> float)

Why does xSquared takes float and returns float?

2

There are 2 answers

2
Sebastian Good On BEST ANSWER

With more information, F# can determine that xSquared is called with float arguments. If you change negXPlusFive to something like "let negXPlusFive x = -x + 5" you would find that it, fog and xSquared would be "int -> int".

1
MichaelGG On

To expand on what Sebastian said and what jleedev tagged, a function like:

let xSquared x = x*x

Can only work on a type that has an operator *. By default, int wins in these situations. It cannot be truly generic because .NET doesn't have a way of representing the constraint "any type that has *".

However, F# supports inlining, which allows functions to be more generic, because they are inlined into each callsite. This allows you to have a function like xSquared that works on floats, ints, etc., -- any type with a * operator.

> let inline xSquared x = x*x;;

val inline xSquared :
   ^a ->  ^b when  ^a : (static member ( * ) :  ^a *  ^a ->  ^b)

Now notice how the function type is ^a -> ^b. This is similar to 'a -> 'b, except the type variables must be statically resolved. Because F# doesn't have typeclasses, this is how operators are handled.

You can actually define your own type with it's own * member to do whatever you desire, and it'd work with xSquared:

type Foo(x) =
    member this.Y = x - 1
    static member (*) (x:Foo, y:Foo) = string <| x.Y * y.Y + 1

let a = Foo(10);;

type Foo =
  class
    new : x:int -> Foo
    member Y : int
    static member ( * ) : x:Foo * y:Foo -> string
  end
val a : Foo

> xSquared a;;
val it : string = "82"

Just open prim-types.fs in your F# distro and poke around. Around line 2200 are the definitions for >>> and others which show off inlining and other nifty things.