Различие в F# и Clojure, когда вызывающие переопределенные функции

В F#:

> let f x = x + 2;;

val f : int -> int

> let g x = f x;;

val g : int -> int

> g 10;;
val it : int = 12
> let f x = x + 3;;

val f : int -> int

> g 10;;
val it : int = 12

В Clojure:

1:1 user=> (defn f [x] (+ x 2))
#'user/f
1:2 user=> (defn g [x] (f x))
#'user/g
1:3 user=> (g 10)
12
1:4 user=> (defn f [x] (+ x 3))
#'user/f
1:5 user=> (g 10)
13

Обратите внимание, что в Clojure новую версию f называют в последней строке. В F# однако все еще называют старую версию f. Почему это и как это работает?

12
задан Michiel Borkent 3 April 2010 в 08:09
поделиться

3 ответа

Как сказал gabe , F # interactive использует затенение значений, когда вы вводите функцию с уже существующим именем (для получения дополнительной информации по слежению см., например, этот вопрос SO ). Это означает, что компилятор F # видит что-то вроде этого, когда вы запускаете свой код:

> let f@1 x = x + 2;; 
> let g@1 x = f@1 x;; 
> g@1 10;; 
val it : int = 12
> let f@2 x = x + 3;; 
> g@1 10;; 
val it : int = 12 

F # использует искаженное имя (например, @), которое вы не можете использовать напрямую, чтобы различать версии значения. С другой стороны, поведение Clojure, вероятно, лучше всего можно понять как большой словарь функций. Используя псевдосинтаксис, примерно так:

> 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

Это должно прояснить различие.

В качестве примечания, есть одна возможная проблема с подходом Clojure (по крайней мере, для такого языка, как F #). Вы можете объявить функцию некоторого типа, использовать ее, а затем следующая команда может изменить тип функции. Если F # использует подход Clojure, как должен работать следующий пример?

> let f a b = a + b;;
> let g x = f x x;;
> let f () = printf "f!";;
> g 0;;

Функция g использует f , как если бы у нее было два параметра типа int , но третья строка меняет тип функции. Это делает подход Clojure немного сложным для языков с проверкой типов.

8
ответ дан 2 December 2019 в 06:08
поделиться

В Clojure символ f захватывает имя f , а в F # - f символ фиксирует значение f . Таким образом, в Clojure каждый раз, когда вы вызываете g , он ищет f , чтобы узнать, к чему это имя относится в данный момент, тогда как в F # каждый вызов g использует значение, которое f имело при первоначальном создании функции g .

12
ответ дан 2 December 2019 в 06:08
поделиться

Гейб и Томас хорошо изучили основы. Обратите внимание: если вы хотите, чтобы F # вел себя так же, как Clojure, вы можете использовать изменяемую привязку и переназначить f :

let mutable f = fun x -> x + 2
let g x = f x

g 10;; // 12

f <- fun x -> x + 3 // note, assign new value, don't create new binding

g 10;; //13
5
ответ дан 2 December 2019 в 06:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: