W SML, jest to legalne mieć w .mli
:η-ekspansja w czystym języku funkcjonalnym
val f : 'a -> 'a
val g : 'a -> 'a
i .ml
:
let f x = x
let g = f
Jeszcze w F #, to zostanie odrzucony:
eta_expand.ml(2,5): error FS0034: Module 'Eta_expand' contains
val g : ('a -> 'a)
but its signature specifies
val g : 'a -> 'a
The arities in the signature and implementation differ. The signature specifies that 'g' is function definition or lambda expression accepting at least 1 argument(s), but the implementation is a computed function value. To declare that a computed function value is a permitted implementation simply parenthesize its type in the signature, e.g.
val g: int -> (int -> int)
instead of
val g: int -> int -> int.
Jednym z rozwiązań jest η-rozszerzenie definicji g:
let g x = f x
Jeśli mój kod jest czysto funkcjonalne (bez wyjątków, bez skutków ubocznych, itp) powinno to być odpowiednik (w rzeczywistości, to może być jeszcze lepiej w odniesieniu do polimorfizmu, w zależności od tego, jak język uogólnia typy: w SML aplikacje cząstkowe nie generują funkcji polimorficznych, ale ich η-ekspansja nie).
Czy istnieje jakakolwiek wada systematycznej rozbudowy η?
Dwie odpowiedzi wymykają się pytaniu o rozszerzenie η :-), a zamiast tego sugerują dodanie nawiasów wokół mojego typu funkcjonalnego. Dzieje się tak, ponieważ, jak widać, F # rozróżnia na poziomie pisania pomiędzy "prawdziwą" definicją funkcji (jak wyrażenia λ i wyliczone definicje, jak w aplikacjach częściowych); prawdopodobnie jest tak dlatego, że wyrażenia λ bezpośrednio mapują się do funkcji CLR, podczas gdy obliczone definicje odwzorowują obiekty delegowane. (Nie jestem pewny tej interpretacji i będę wdzięczny, jeśli ktoś bardzo znany z F # mogłyby wskazywać odwoływać dokumenty opisujące ten.)
Rozwiązaniem byłoby systematycznie dodać nawiasy do wszystkie typy funkcyjne w .mli
, ale Obawiam się, że może to prowadzić do nieefektywności. Innym rozwiązaniem byłoby wykrycie obliczonych funkcji i dodanie nawiasów odpowiednich typów w .mli
. Trzecim rozwiązaniem byłoby η-rozwinięcie oczywistych przypadków i nawrócenie pozostałych.
Nie jestem wystarczająco zaznajomiony z obiektami F #/CLR, aby zmierzyć, które z nich powodują znaczną wydajność lub łączą się z karami.
Po prostu ustaw "val g: (" a -> "a)'. Jest to znana funkcja/błąd systemu typu F #. –
Znowu "po prostu zrób to" - prawdopodobnie jeśli wyrażenia λ i funkcje obliczone nie mają typów wymiennych, to nie bez powodu. Co więcej, jest to kod wygenerowany automatycznie, dlatego sprawa jest nieco bardziej skomplikowana niż zwykłe ręczne dodanie kilku nawiasów ... –
Istnieje różnica między tymi dwoma w tym przypadku, jeden jest wkompilowany w metodę, a drugi w statyczny. Func 'własność. Zgodność nie jest dwukierunkowa (tj. 'A -> b: <: (a -> b)', ale nie ma znaczenia (a -> b): <: a -> b'). –