2012-09-20 9 views
6
let inline myfunction x y = ... 

let inline mycurried = myfunction x // error, only functions may be marked inline 

Wydaje się niemożliwe, aby jawnie inline funkcji curry. Zawsze, gdy wywoływana jest nazwa mycurried, nie otrzyma ona inlined, nawet jeśli myfunction ma wartość inlined, czy jest poprawna?Czy funkcje wolne od punktów były w stanie wstawiać?

Czy można to zatem uznać za jedną z wad funkcji curry?

Odpowiedz

5

Myślę, że pytanie o to, czy point-free funkcja może być inlined czy nie.

Ograniczenie, które Państwo znaleźli, nie jest spowodowane funkcją curry. Należy zauważyć, że w twoim przykładzie funkcja curried znajduje się po prawej stronie, po lewej stronie masz funkcję bez punktów.

F # zezwala tylko na funkcje wbudowane, a nie stałe.

Zasada, którą możesz uważać, że może to być uznane za błąd, biorąc pod uwagę, że wnioskowanie typu jest wystarczająco inteligentne, aby dowiedzieć się, że jest to funkcja (bez punktów), ale przeczytaj uwagi od Tomas dotyczące efektów ubocznych.

Podobno gdy kompilator znajdzie się po lewej stronie tylko identyfikator nie jest on z tego błędu:

let inline myfunction x y = x + y 

let inline mycurried = myfunction 1 

--> Only functions may be marked 'inline' 

Jak powiedział Brian obejście jest dodanie wyraźnego parametr po obu stronach:

let inline mycurried x = (myfunction 1) x 

ale wtedy twoja funkcja nie jest już wolna od punktu, jest taka sama jak:

let inline mycurried x = myfunction 1 x 

Innym sposobem może być dodanie jawnego ogólnego parametru:

let inline mycurried<'a> = myfunction 1 

, gdy ogólne parametry są wyraźnie widoczne po lewej stronie, którą kompiluje.

życzę oni usunąć komunikat o błędzie i włącz go ostrzeżenie, coś takiego:

Since only functions can be 'inline' this value will be compiled as a function. 

UPDATE

Tomas Dzięki za odpowiedź (i swojej downvote).

Moja osobista opinia powinna być ostrzeżeniem, więc zdajesz sobie sprawę, że semantyczność twojego kodu ostatecznie się zmieni, ale to od ciebie zależy, co będziesz robić.

Można powiedzieć, że jest inline „tylko optymalizacja” ale to nie do końca prawda:

. Proste włączenie wszystkich funkcji w linii nie gwarantuje optymalnego kodu.

. Możesz użyć ograniczeń statycznych, a następnie użyć wbudowanego.

Chciałbym móc definiować moje (rodzaj) stałych generycznych, tak jak robi to biblioteka F # (np. GenericZero i GenericOne). Wiem, że mój kod będzie czysty, więc nie obchodzi mnie, czy jest wykonywany za każdym razem.

+0

Należy zauważyć, że zmiana wiązania let z _value_ ("let x = ...") na _function_ ("let x arg = ...") może zmienić znaczenie funkcji, jeśli wyrażenie użyte do obliczenia funkcja ma pewne efekty. W pierwszym przypadku efekty będą oceniane raz, a w drugim będą wielokrotnie oceniane. Jeśli chcesz, aby efekty były oceniane tylko raz, nie możesz użyć 'inline'. Jeśli chcesz wykonać je kilka razy, to myślę, że uczciwie jest dodać dodatkowy parametr. –

+0

Dodanie ogólnego parametru to _very subtle_, ponieważ nadal wygląda jak wartość, ale faktycznie zachowuje się jak funkcja (tzn. Efekty są wielokrotnie oceniane), więc nie poleciłbym tego. (Poza tym jestem prawie pewien, że zachowanie jest właściwie niezdefiniowane - tzn. Przyszła wersja kompilatora może zdecydować o ocenie efektów tylko raz dla każdego argumentu typu ogólnego). –

+0

Komunikat o błędzie nie ma sensu w czystych językach (takich jak Haskell), ale uważam, że zapobieganie przypadkowej zmianie zachowania programu po dodaniu 'inline' tylko w celu zoptymalizowania go jest bardzo dobrą decyzją. –

4

Chyba po prostu trzeba dodać wyraźnie parametr dla obu stron (chociaż nie próbowałem):

let inline myfunction x y = ... 

let inline mycurried y = myfunction 42 y // or whatever value (42) 
2

Kompilator zezwala tylko na inline na udostępnianie wiązań definiujących funkcję. Jest to w istocie to samo, co dzieje się with F# value restriction (i zobacz also here). Jak mówi Brian, możesz łatwo obejść to poprzez dodanie parametru do swojej funkcji.

Dlaczego to ograniczenie istnieje? Gdyby go tam nie było, dodanie inline zmieniło znaczenie twoich programów i byłoby źle!

Załóżmy, że masz funkcję tak (co stwarza stan zmienny i zwraca funkcję licznika):

let createCounter n = 
    let state = ref n 
    (fun() -> incr state; !state) 

Teraz następujący kod:

let counter = createCounter 0 

... tworzy jedną globalną funkcję, której możesz użyć wiele razy (zadzwoń pod numer counter()), a otrzymasz unikalne liczby całkowite zaczynające się od 1. Jeśli możesz oznaczyć ją jako inline:

let inline counter = createCounter 0 

... wtedy za każdym razem, gdy używasz counter(), kompilator powinien zastąpić to przy pomocy createCounter 0(), aby otrzymać 1 za każdym razem, gdy wywołasz licznik!

+0

Masz rację. Właściwie możesz skompilować go jako wbudowany, podając sztuczkę, o której wspomniałem: niech inline counter <'a> = ...... W każdym razie nadal wolałbym ostrzeżenie niż błąd kompilacji i poleganie na obejściach/trikach. – Gustavo

+0

@Gustavo Myślę, że to więcej niż uczciwe, aby uzyskać błąd kompilatora, gdy inline (co jest tak naprawdę tylko optymalizacji) zmieni semantykę kodu. Błąd po prostu informuje, że kompilator _cannot_ wartości inline (i to ma bardzo dobry sens). Jeśli chcesz (i możesz) zmienić wartość w funkcję, to dobrze, że musisz to zrobić jawnie, ponieważ musisz zastanowić się, czy to daje ci to, czego chcesz. –

+0

@Gustavo I tak, możesz skompilować kod, jeśli napiszesz 'let inline counter <'T> = createCounter 0' i myślę, że to jest złe. Oznacza to, że zawsze otrzymasz '1', gdy wywołasz' counter <_>() 'i to nie jest zamierzone zachowanie. –

Powiązane problemy