hubFS: THE place for F#

. . . are you on The Hub?
Welcome to hubFS: THE place for F# Sign in | Join | Help
in Search

Function Execution

Last post 10-08-2009, 7:47 by mobrien. 8 replies.
Sort Posts: Previous Next
  •  10-07-2009, 9:08 11952

    Function Execution

    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

    "Put your hand on a hot stove for a minute, and it seems like an hour. Sit with a pretty girl for an hour, and it seems like a minute. That's relativity." - Einstein
  •  10-07-2009, 9:59 11953 in reply to 11952

    Re: Function Execution

    mobrien:
    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.
  •  10-07-2009, 10:09 11954 in reply to 11953

    Re: Function Execution

    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
    "Put your hand on a hot stove for a minute, and it seems like an hour. Sit with a pretty girl for an hour, and it seems like a minute. That's relativity." - Einstein
  •  10-07-2009, 11:05 11955 in reply to 11954

    Re: Function Execution

    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
    "Put your hand on a hot stove for a minute, and it seems like an hour. Sit with a pretty girl for an hour, and it seems like a minute. That's relativity." - Einstein
  •  10-07-2009, 12:18 11957 in reply to 11955

    Re: Function Execution

    mobrien:
    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:

    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:

    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
  •  10-07-2009, 12:39 11959 in reply to 11957

    Re: Function Execution

    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

    "Put your hand on a hot stove for a minute, and it seems like an hour. Sit with a pretty girl for an hour, and it seems like a minute. That's relativity." - Einstein
  •  10-07-2009, 20:33 11961 in reply to 11959

    Re: Function Execution

    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.
    Paulmichael Blasucci
  •  10-07-2009, 20:39 11963 in reply to 11961

    Re: Function Execution

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

    let foo _ = printfn "foo" (* fsi reports the type as 'a -> unit *)
    let bar () = printfn "bar" (* fsi reports the type as unit -> unit *)
    Paulmichael Blasucci
  •  10-08-2009, 7:47 11965 in reply to 11963

    Re: Function Execution

    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
    "Put your hand on a hot stove for a minute, and it seems like an hour. Sit with a pretty girl for an hour, and it seems like a minute. That's relativity." - Einstein
View as RSS news feed in XML
Powered by Community Server, by Telligent Systems