2016-10-03 11 views
7

jestem zadowolony z koncepcją pure function na bardzo prostych przykładów, jak ...Dlaczego ta implementacja czystej funkcji nie jest uważana za mającą zewnętrzne zależności?

function addTwo(val){ 
    return val + 2; 
} 

Biorąc pod uwagę te same argumenty, że daje te same wyniki, co prowadzi do referencyjna Przejrzystość i dobrego kodu deterministycznego.

Ale wtedy ja natknąłem przykładów jak te (zaczerpnięte z professor frisby mostly adequate guide, ale znalazłem podobne przykłady na innych książek FP JS)

//pure 
var signUp = function(Db, Email, attrs) { 
    return function() { 
    var user = saveUser(Db, attrs); 
    welcomeUser(Email, user); 
    }; 
}; 

var saveUser = function(Db, attrs) { 
    ... 
}; 

var welcomeUser = function(Email, user) { 
    ... 
}; 

a ja nie rozumiem, dlaczego nie jest uważane zewnętrzna zależność (tak, nieczysta) od połączenia z saveUser lub welcomeUser.

Wiem, że z punktu widzenia funkcji/IO, signUp zawsze zwraca "taką samą" (odpowiednik) funkcję przewodową, ale wydaje mi się to dziwne.

Trudno mi zrozumieć, dlaczego nawet

function multiplyBy(times){ 
    return value => value * times; 
} 
const fiveTimes = multiplyBy(5); 
fiveTimes(10); 

jest uważany pure. Z zwróconej funkcji POV, dostęp do times jest odnośnikiem w łańcuchu zasięgu, może pochodzić z najbliższego zewnętrznego zasięgu lub z zewnątrz (jak globalny zasięg).

Ktoś chce przynieść trochę światła?

+1

W jaki sposób "czasy" mogą pochodzić spoza najbliższego zewnętrznego zakresu? –

+1

Załóżmy, że były to 'const multiply = ...' (ES2015). Czy nadal masz pytanie, czy 'fiveTimes' jest czysty? JavaScript nie jest przede wszystkim językiem funkcjonalnym (chociaż może być w większości używany w ten sposób), więc jeśli zmienność tych identyfikatorów jest tym, co Cię niepokoi, odpowiedź może być "zgodnie z konwencją, dopóki nie będziemy mogli użyć ES2015, zakładamy, że opuścisz funkcję identyfikatory niezmienione. " –

+0

@ squint w moim snippet nie jest inny sposób, ale co próbuję powiedzieć (nie jestem native speakerem języka angielskiego) jest to, że jeśli wziąć zwróconą funkcję w izolacji i zbadać ciało (wartość * razy) razy nie występuje w podpisie, więc pobiera z zakresu poprzez wyszukiwanie w łańcuchu zasięgu. Dlatego wydaje się dość nieczyste. – sminutoli

Odpowiedz

16

Moje wyjaśnienie dla czystości funkcji w JavaScript jest takie, że nie ma czegoś takiego jak binarny "czysty" lub "nieczysty", ale raczej spektrum pewności, że funkcja będzie zachowywać się w sposób przewidywalny. Istnieje wiele rodzajów sztuczek, które można grać, aby funkcja, która wydaje się czysta, nie jest, na przykład przez przekazanie obiektu z efektem ubocznym.

Tak więc, gdy zdamy sobie sprawę, że czystość jest o stopień zaufania, możemy zapytać, jak pewny jestem, że jakaś funkcja będzie zachowywać się tak, jak się spodziewam? Jeśli ta funkcja odwołuje się do innej funkcji, to na pewno, czy druga funkcja jest czysta? Co więcej, czy jesteś pewien, że identyfikator, który odwołuje się do tej innej funkcji, nie jest/nie może zostać ponownie przypisany do wskazania innej funkcji, o której nie wiesz?

Ja osobiście koduję moje programy, więc prawie nigdy nie ponownie zdefiniowałem identyfikatora wskazującego na funkcję, szczególnie jeśli ta funkcja jest zadeklarowana, a nie tylko wyrażenie funkcji. W ten sposób czuję się bardzo pewny (powiedzmy 99,99%), że jeśli foo(..) dzwoni pod numer bar(..) i jestem przekonany, że bar(..) jest niezawodnie czysty, to foo(..) jest również niezawodnie czysty, ponieważ wiem, że nie zmienię przypisania bar(..) na żadne inne działają i powodują zaskakujące wyniki.

Niektórzy ludzie posuwają się nawet do określenia swoich identyfikatorów funkcji za pomocą const fn = function ... Nie wydaje mi się, żeby to wszystko pomogło ... prawdopodobnie wzrósłoby mój poziom zaufania z 99,99% do 99,999%. To nie przesuwa igły na tyle, by uzasadnić jej użycie, IMO.

Co więcej, na zamknięciu twojego pytania: jeśli funkcja wewnętrzna zamyka się na zmiennej zewnętrznej, która wciąż jest zawarta w czystej funkcji, i nic nie przypisuje tej zmiennej, to jest ona stała, więc mój poziom zaufania jest bardzo wysoka w przewidywalności.

Ale znowu, na wynos jest to, że czystość funkcji w JS dotyczy poziomu pewności, a nie bezwzględnego binarnego tak lub nie.

+0

________________ Poziom_dźwięku_ brzmi odpowiednio dla dwóch programistów pracujących nad tym samym projektem, ale nie dla języka programowania, który jest istotną częścią sieci. Przerażający! – ftor

+2

Myślę o * poziomie zaufania * jako luźnej umowie między pisarzem i czytelnikiem fragmentu kodu. Autor może zrobić więcej lub mniej, aby zwiększyć efektywność tej umowy, co powoduje mniej lub bardziej czytelność dla czytelnika. –

5

Definicja czystej funkcji jest:

funkcja, która nie zawsze ocenia samą wartość wyników przy takiej samej wartości argumentu (e), oraz że nie powoduje semantycznie zaobserwowania efektu ubocznego lub wyjście , takie jak mutacja zmiennego obiektu lub wyjście do urządzeń wejścia/wyjścia.

"Posiadanie zależności" nie odgrywa żadnej roli w definiowaniu czystej funkcji. Ważne jest tylko to, czy funkcja ma jakieś efekty uboczne i czy jej wynik zależy od zewnętrznego stanu. Jeśli funkcja zachowuje się dokładnie tak samo i zawsze daje taki sam wynik, otrzymując to samo wejście, jest czysta. Jeśli funkcja ma jakieś efekty uboczne (modyfikuje stan globalny) lub zachowuje się inaczej w zależności od stanu zewnętrznego, jest nieczysta. Funkcja może być zależna od (read: call) innej funkcji jako części swojej operacji; tak długo jak ta inna funkcja jest również czysta, to nie zanieczyszcza ona czystości.

Przykład, który pokazujesz, jest czysty, ponieważ działa tylko na jego wejściu i zawsze zwraca dokładnie to samo wyjście, gdy zostanie wywołany z tym samym wejściem. Zauważ, że sama funkcja niczego nie "robi". Nie wywołuje bazy danych ani nie wywołuje żadnych skutków ubocznych. Wszystko, co robi, to zwrócenie funkcji. Ale ta zwracana funkcja jest zawsze taka sama, jeśli dane wejściowe są takie same. Ta zwracana funkcja jest w rzeczywistości nieczysta; ale funkcja, która ją wytworzyła, nie jest.

+1

* "Pokazany przykład signUp jest czysty, ponieważ działa tylko na jego wejściu i zawsze zwraca dokładnie to samo wyjście po wywołaniu z tym samym wejściem." * ... chyba że zmienisz to, co 'saveUser' i' welcomeUser' odnoszą się do , co moim zdaniem jest sednem pytania. –

+0

Tak, oczekiwałem, że saveUser i welcomeUser również są parami, może pokazują takie przykłady, aby "zachować prostotę" i zacząć pojmować koncepcję. – sminutoli

+0

@deceze dzięki za szczegółową odpowiedź! – sminutoli

Powiązane problemy