As gabe said, F# interactive uses shadowing of values when you enter a function with a name that already exists (for more info on shadowing, see for example this SO question). This means that the F# compiler sees something like this when you run your code:
> let f@1 x = x + 2;;
> let g@1 x = f x;;
> g@1 10;;
val it : int = 12
> let f@2 x = x + 3;;
> g@1 10;;
val it : int = 12
F# uses some mangled name (like @) that you cannot use directly to distinguish between versions of the value. On the other hand, Clojure behavior can be probably best understood as a big dictionary of functions. Using psudo-syntax, something like this:
> symbols[f] = fun x -> x + 2;;
> symbols[g] = fun x -> symbols[f] x;;
> symbols[g] 10;;
val it : int = 12
> symbols[f] = fun x -> x + 3;;
> symbols[g] 10;;
val it : int = 13
This should make the distinction quite clear.
As a side-note, there is one possible problem with the Clojure approach (at least for language like F#). You can declare a function of some type, use it and then, the next command can change the type of the function. If F# used the Clojure approach, how should the following example work?
> let f a b = a + b;;
> let g x = f x x;;
> let f () = printf "f!";;
> g 0;;
The function g
uses f
as if it had two parameters of type int
, but the thrid line changes the type of the function. This makes the Clojure approach a bit tricky for type-checked languages.