Reputation: 43
I test some simple F# code for "if" expression, but the result is unexpected for me:
> let test c a b = if c then a else b;;
val test : bool -> 'a -> 'a -> 'a
However
> test true (printfn "a") (printfn "b");;
a
b
val it : unit = ()
I'd expect only "a" is printed out but here I got both "a" and "b". I wonder why it comes out this way? Thanks!
Upvotes: 4
Views: 240
Reputation: 211
Here's a lazy computation version. F# seems to require type annotation in order to use the Force method here. A bit messy, but it does work.
> let test c a b = if c then (a:Lazy<unit>).Force else (b:Lazy<unit>).Force;;
val test : bool -> Lazy<unit> -> Lazy<unit> -> (unit -> unit)
> test true (lazy (printfn "a")) (lazy (printfn "b"))();;
a
val it : unit = ()
>
Upvotes: 0
Reputation: 118865
To be very clear, it's for the same reason that
let f x = x + 1
f (3+5)
evaluates (3+5)
before calling f
. Pretty much every language except Haskell works like this (modulo languages with macros).
Upvotes: 4
Reputation: 13862
Hao is correct. You have to wrap those expressions in functions to make them lazy. Try this.
let test c a b = if c then a() else b();;
test true (fun () -> printfn "a") (fun () -> printfn "b");;
Upvotes: 7
Reputation: 10228
Possibly because both printfn function calls are evaluated before the test call ever occurs? If you want both the function calls to be delayed until they're actually used, you might want lazy computation or macros (which F# doesn't have).
Upvotes: 6