I'm wondering if the F# compiler has an optimization that will make it so that the sqrt5 and Phi functions only execute once, no matter how many times the fibn function is called, since the results of those functions are always constant.

let sqrt5 = sqrt 5.0

let Phi = (1.0 + sqrt5) / 2.0

let fibn n = Phi ** float n / sqrt5 |> round |> int

let fib2 = Seq.unfold (fun index -> Some (fibn index,index + 1)) 1

I'm trying to figure out if the compiler automagically makes this happen or if I have to make it happen.

Thx!

m

In the code that you've written, sqrt5 and Phi are not functions but values (they don't take any arguments). As such, their definitions will never be re-evaluated.

By on 10/7/2009 9:59 AM ()

Ah! Ok, that makes sense.

Now that leads to another question, when does it become a function (Evaluated for each call) and not a value? For example what if I threw a DateTime.Now.Seconds in the equation?

Or put another way; how do you know when its considered a function and when its considered a value?

Thx!

m

By on 10/7/2009 10:09 AM ()

Well, now that I think about it, it's probably that the compiler can look through the call graph and see if it's all deterministic. So if thats the case then it's a value. Otherwise if there is some non deterministic functions in the call graph it's considered a function.

So just by looking at my code above you can see that it's all deterministic and thus a value.

Just a wild guess.... Am I close? :)

m

By on 10/7/2009 11:05 AM ()

Well, now that I think about it, it's probably that the compiler can look through the call graph and see if it's all deterministic. So if thats the case then it's a value. Otherwise if there is some non deterministic functions in the call graph it's considered a function.

So just by looking at my code above you can see that it's all deterministic and thus a value.

Just a wild guess.... Am I close? :)

m

Not quite... in general it's impossible to know if something is deterministic, so the compiler uses a much simpler scheme.

For top level definitions, something is a value if it doesn't take parameters. For instance, given the two definitions:

1
2
let now = System.DateTime.Now
let add x y = x + y

"now" is a value, and will never change. add is a function taking two arguments, and each time both arguments are supplied, the definition on the right will be evaluated to give the return value.

However, when defining .NET classes, things become more complicated, because classes can contain fields, methods, events, properties, etc. Properties are re-evaluated whenever they are gotten, and DateTime.Now is a property, which is why the value appears to change over time.

Things can also be a bit confusing when using functions in a first-class way. For instance:

1
2
3
let myFun =
  let time = System.DateTime.Now
  fun () -> System.DateTime.Now - time

Here, myFun is a value (which happens to be a function!), and its definition is only evaluated once (so, in particular, "time" is only ever set once, when myFun is first defined). However, calling the myFun function then results in the evaluation of the function's body (that is, the right hand side of the last line of myFun's definition, which calls System.DateTime.Now and subtracts the original time).

-Keith

By on 10/7/2009 12:18 PM ()

Ah, now it's starting to all make sense. So thats why I have to have a wildcard parameter on a function that I want executed every time but has no parameters. Like this:

module Display

let Clear _ = Console.Clear()

Display.Clear ()

I wasn't really clear (No pun intended) on why I had to do this but now it makes sense.

Thanks for breaking this down for me!

m

By on 10/7/2009 12:39 PM ()

While this approach does work, idiomatic F# would just use a Unit (which is written as two parentheses).

let clear () = Console.Clear()

I believe there is a slight difference in the code generated for these two forms. This would be due to automatic generalization and type inference. Of course, I haven't tested this... so don't hold me to it.

By on 10/7/2009 8:33 PM ()

I got curious, so I just went and double-checked. The wildcard does, in fact, generate different code than the unit. This can be seen in the type signatures of the following two sample methods (or by comparing the IL)...

1
2
3
4
let foo _ = printfn "foo" (* fsi reports the type as 'a -> unit *)

let bar () = printfn "bar" (* fsi reports the type as unit -> unit *)
By on 10/7/2009 8:39 PM ()

Yeah, I see what your saying, that does make more sense. So I would instead make the parameter a unit (Or void in C#):

module Display

let Clear () = Console.Clear()

Display.Clear ()

Thanks for pointing this out.

m

By on 10/8/2009 7:47 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper