Ponieważ czystość parametru wejściowego jest nieznana do czasu działania, czy funkcja jest natychmiast uważana za nieczystą, jeśli przyjmuje funkcję jako parametr wejściowy?
Powiązane: jeśli funkcja stosuje funkcję czystą, która jest zdefiniowana poza funkcją, ale nie jest przekazywana jako parametr, czy nadal jest czysta, jeśli spełnia kryteria braku efektów ubocznych, a wynik zależy wyłącznie od danych wejściowych?
Dla kontekstu piszę kod funkcjonalny w JavaScript.
functional-programming
pure-function
Dancrumb
źródło
źródło
foo = function(function bar){ print(bar.toString()) }
foo = function(function bar) { return 3; }
jest czysty i przyjmuje funkcję jako argument.toString()
(tj. Ten, który można znaleźć w obiekcie Java).Odpowiedzi:
Dopóki wszystkie wartości użyte w funkcji są zdefiniowane wyłącznie przez jej parametry, jest to funkcja czysta.
Aspekt wyjściowy jest za każdym razem taki sam dla tych samych danych wejściowych jest kontrolowany przez to, czy parametry są czyste. Jeśli założymy, że parametry (takie jak argument funkcji) są również czyste, to jest czyste.
W języku takim jak Javascript, gdzie czystość nie jest wymuszona, oznacza to, że możliwe jest, aby w przeciwnym razie czysta funkcja miała nieczyste zachowanie, wywołując nieczystą funkcję przekazaną jako parametr.
Oznacza to skutecznie, że w przypadku języków, które nie wymuszają czystości (tj. Prawie wszystkich), niemożliwe jest zdefiniowanie funkcji czystej, która wywołuje funkcje przekazywane jako argumenty. Nadal przydatne jest pisanie ich tak czysto, jak to możliwe, i rozumowanie ich jako czystych funkcji, ale musisz zachować ostrożność, ponieważ założenie, że jest czyste, zostanie złamane, jeśli podasz niewłaściwe argumenty.
Z mojego doświadczenia w praktyce nie jest to zwykle wielka sprawa - zdarza się, że nieczyste funkcje mogą być używane jako argumenty funkcji dla funkcji czystych.
źródło
areaOfCircle r => Math.Pi * r * r
, czyareaOfCircle
nie będzie ona czysta, ponieważ nie używa ona tylko parametrów?f(f2)
że funkcja, która się wywołujef2
, nie zależy w żaden sposób od niczegof2
. Funkcja, która może wywoływać dowolne przekazane funkcje, nie jest czysta.function compose(f, g) {return function h(x) {return f(g(x));};}
, co jest czyste pomimo przyjmowania funkcji jako argumentu.find
procedurę nieczystemu predykatowi, który zwraca „prawda” dla trzeciego pasującego elementu, który napotyka, lub jakiegoś takiego nonsensu.Nie. Przeciwprzykład:
Nie ma znaczenia, czy
other_function
jest to funkcja czysta, czy nieczysta, czy nie.pure
Działanie jest czyste.Inne kontrprzykład:
Ta funkcja jest czysta, nawet jeśli
x
jest nieczystą funkcją.identity(impure_function)
zawsze wróciimpure_function
, bez względu na to, ile razy powtórzysz połączenie. Nie ma znaczenia, czyidentity(impure_function)()
zawsze zwraca to samo; wartość zwracana przez funkcję nie wpływa na jej czystość.Ogólnie rzecz biorąc, jeśli funkcja może wywołać funkcję, została przekazana jako argument, nie jest czysta. Na przykład funkcja
function call(f) {f();}
nie jest czysta, ponieważ chociaż nie wspomina o żadnym stanie globalnym lub zmiennym,f
może być coś takiego,alert
co powoduje widoczne skutki uboczne.Jeśli funkcja przyjmuje funkcje jako argumenty, ale ich nie wywołuje ani nie wywołuje, wówczas może być czysta. Może nadal być nieczyste, jeśli zrobi coś innego. Na przykład
function f(ignored_function) {alert('This isn't pure.');}
jest nieczyste, mimo że nigdy nie dzwoniignored_function
.źródło
Technicznie tak, chyba że w twoim języku jest jakiś sposób na zagwarantowanie, że funkcja wprowadzania danych jest również czysta.
Tak. Skupmy się więc na tym, co ważne. Wywołanie funkcji czystej lub nie jest samo w sobie przydatne. Czyste funkcje są przydatne, ponieważ wytwarzanie tego samego wyniku dla dowolnego wejścia i niezależne od stanu lub powodujące skutki uboczne jest bardzo użytecznym zestawem właściwości. Oznacza to, że po uruchomieniu funkcji można „zapamiętać” odpowiedź na to wejście i zawsze będzie ona prawdziwa. Nie musisz też ponownie uruchamiać tej funkcji, aby generować efekty uboczne. I można uruchomić tę funkcję równolegle (lub poza kolejnością) z innymi funkcjami i wiem, że nie będzie miał żadnych ukrytych interakcji, które zachowują się źle.
Te użyteczne właściwości nadal obowiązują, jeśli funkcja wykonuje inne funkcje tylko do odczytu, niezależnie od tego, w jaki sposób się do nich odwołuje.
źródło
Jak powiedział Telastyn: Technicznie tak, chyba że w twoim języku jest jakiś sposób na zagwarantowanie, że funkcja wprowadzania danych jest również czysta.
To nie jest hipotetyczne, istnieją naprawdę dobre sposoby, aby to zagwarantować. Przynajmniej w silnie napisanym języku.
Taką czystą ~ funkcję, którą napisalibyście w JavaScript jako
można przetłumaczyć bezpośrednio na Haskell:
Teraz w JavaScript możesz robić złe rzeczy, takie jak
W Haskell nie jest to możliwe . Powodem jest to, że coś takiego jak efekt uboczny
console.log()
musi zawsze mieć typ wynikuIO something
, a nie tylkosomething
sam.Aby to wyrażenie mogło sprawdzić typ, musielibyśmy podać
foo
podpis typuAle okazuje się, że nie mogę go już zaimplementować: ponieważ
IO
w wyniku tego funkcja argumentu nie może go użyć w sobiefoo
.Jedynym sposobem, w jaki mógłbym użyć
IO
akcjifoo
jest to, że wynikfoo
maIO Int
sam typ :Ale w tym momencie z podpisu jasno wynika,
foo
że nie jest to również czysta funkcja.źródło
unsafeIO
:-)IO
. Nawiasem mówiąc, można go również użyć do wywołania chaosu, ukrywając skutki uboczne w „czystej” funkcji, ale w Haskell jest to naprawdę niebezpieczne, ponieważ nie ma naprawdę niezawodnego sposobu określenia kolejności oceny czystych funkcji.unsafeIO
; jest to klapa ratunkowa ostatniej szansy, która omija system gwarantowany przez system typów, a zatem twój nie jest dobrym pomysłem.Nie, nie jest.
Jeśli przekazana funkcja jest nieczysta ORAZ twoja funkcja wywołuje przekazaną funkcję, wówczas twoja funkcja zostanie uznana za nieczystą.
Relacja czysta / nieczysta jest trochę podobna do synchronizacji / asynchronizacji w JS. Możesz swobodnie używać czystego kodu od nieczystego, ale nie na odwrót.
źródło