views:

271

answers:

2

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?

+3  A: 

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".

Sebastian Good
It looks like F# infers types of argument depending on how much F# knows about the context in which the method was created. Thanks.
Sung Meister
F# only does this when it has to restrict the value's polymorphism. In this case, x cannot be 'a; it must restrict it to a single type.
MichaelGG
+10  A: 

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.

MichaelGG
Thanks, MichaelGG for more detailed explanations
Sung Meister
Cool, I learnt something here!
Benjol