Una funzione è immediatamente impura se prende una funzione come parametro?

17

Poiché la purezza di un parametro di input è uno sconosciuto fino al runtime, una funzione è immediatamente considerata impura se accetta una funzione come parametro di input?

Correlato: se una funzione applica una funzione pura definita al di fuori della funzione, ma non viene passata come parametro, è ancora pura se soddisfa i criteri di assenza di effetti collaterali e l'output dipende unicamente dall'input?

Per contesto, sto scrivendo codice funzionale in JavaScript.

    
posta Dancrumb 23.10.2015 - 15:41
fonte

5 risposte

22

Finché tutti i valori utilizzati nella funzione sono definiti esclusivamente dai relativi parametri, è una funzione pura.

Il facet che l'output è lo stesso ogni volta per lo stesso input è controllato dal fatto che i parametri siano puri. Se si assume che i parametri (come un argomento di funzione) siano puri, allora è puro.

In un linguaggio come Javascript in cui la purezza non è applicata, questo significa che è possibile rendere una funzione altrimenti pura avere un comportamento impuro richiamando una funzione impura passata come parametro.

Ciò significa in effetti che per le lingue che non impongono la purezza (ovvero quasi tutte), è impossibile definire una funzione pura che richiama funzioni passate come argomenti. È ancora utile scriverle nel modo più puro possibile, e ragionare su di esse come pure funzioni, ma devi fare attenzione perché l'assunto che sia puro verrà infranto se passi gli argomenti sbagliati.

Nella mia esperienza pratica, di solito non è un grosso problema - trovo raro che le funzioni impure vengano utilizzate come argomenti di funzione per le funzioni pure.

    
risposta data 23.10.2015 - 15:56
fonte
19

Since the purity of an input parameter is an unknown until runtime, is a function immediately considered impure if it takes a function as an input parameter?

No. Controesempio:

function pure(other_function) {
    return 1;
}

Non importa se other_function è una funzione pura, una funzione impura o non una funzione. La funzione pure è pura.

Altro controesempio:

function identity(x) {
    return x;
}

Questa funzione è pura, anche se x è una funzione impura. identity(impure_function) restituirà sempre impure_function , indipendentemente dal numero di ripetizioni della chiamata. Non importa se identity(impure_function)() restituisce sempre la stessa cosa; il valore di ritorno del valore restituito di una funzione non influisce sulla sua purezza.

In generale, se una funzione può chiamare una funzione è stata passata come argomento, non è pura. Ad esempio, una funzione function call(f) {f();} non è pura, perché anche se non fa menzione di nessuno stato globale o mutevole, f potrebbe essere qualcosa come alert che causa effetti collaterali visibili.

Se una funzione assume funzioni come argomenti, ma non li chiama o non li chiama, può essere pura. Potrebbe essere ancora impuro se fa qualche altra cosa impura. Ad esempio, function f(ignored_function) {alert('This isn't pure.');} è impuro, anche se non chiama mai ignored_function .

    
risposta data 23.10.2015 - 19:48
fonte
12

Since the purity of an input parameter is an unknown until runtime, is a function immediately considered impure if it takes a function as an input parameter?

Tecnicamente, sì, a meno che non ci sia un modo nella tua lingua per garantire che anche la funzione di input sia pura.

if a function applies a pure function that is defined outside of the function, but is not passed in as a parameter, is it still pure if it fulfills the criteria of having no side effects and output depends solely on input?

Sì. Quindi concentriamoci su ciò che conta qui. Chiamare una funzione pura o no non è di per sé utile. Le funzioni pure sono utili perché produrre lo stesso output per qualsiasi input e non dipende dallo stato o avere effetti collaterali è un insieme di proprietà molto utile. Significa che una volta che la tua funzione è stata eseguita, puoi "ricordare" la risposta per quell'input e sarà sempre vera. Inoltre, non è necessario eseguire nuovamente la funzione per generare effetti collaterali. E puoi eseguire quella funzione in parallelo (o fuori uso) con altre funzioni e sapere che non avranno interazioni nascoste che si comportano male.

Queste proprietà utili sono ancora valide se la funzione utilizza altre funzioni di sola lettura per svolgere il proprio lavoro, indipendentemente dal modo in cui le fa riferimento.

    
risposta data 23.10.2015 - 17:38
fonte
5

Come ha detto Telastyn: Tecnicamente, sì, a meno che non ci sia un modo nella tua lingua per garantire che anche la funzione di input sia pura.

Non è ipotetico, ci sono davvero buoni modi per garantirlo. Almeno in un linguaggio strongmente tipizzato.

Una funzione così pura che avresti scritto in JavaScript come

function foo(f) {
   return f(1) + 2;
}

può essere tradotto direttamente in Haskell:

foo :: (Int -> Int) -> Int
foo f = f 1 + 2

Ora, in JavaScript puoi fare cose cattive come

js> foo (function(x) {console.log("muharhar"); return 0})
muharhar
2

Questo non è possibile in Haskell . Il motivo è che qualcosa di effetto collaterale come console.log() deve sempre avere un tipo di risultato IO something , non solo something da solo.

GHCi> foo (\x -> print "muarhar" >> return 0)

<interactive>:7:12:
    Couldn't match expected type ‘Int’ with actual type ‘IO b0’
    In the expression: print "muarhar" >> return 0
    In the first argument of ‘foo’, namely
      ‘(\ x -> print "muarhar" >> return 0)’
    In the expression: foo (\ x -> print "muarhar" >> return 0)

Per questa espressione di typecheck, dovremmo dare a foo la firma del tipo

foo :: (Int -> IO Int) -> Int

Ma risulta che non posso più implementarlo: perché la funzione argomento ha IO nel suo risultato, non posso usarla entro foo .

<interactive>:8:44:
    Couldn't match expected type ‘Int’ with actual type ‘IO Int’
    In the first argument of ‘(+)’, namely ‘f 1’
    In the expression: f 1 + 2

L'unico modo per utilizzare un'azione IO in foo è se il risultato di foo ha tipo IO Int stesso:

foo :: (Int -> IO Int) -> IO Int
foo f = do
   f1 <- f 1
   return (f1 + 2)

Ma a questo punto è chiaro dalla firma di foo che non è nemmeno una funzione pura.

    
risposta data 23.10.2015 - 23:59
fonte
0

No, non lo è.

Se la funzione passata è impura E la tua funzione chiama la funzione passata, la tua funzione sarà considerata impura.

La relazione pura / impura è un po 'come sync / async in JS. Puoi usare liberamente il codice puro da impuro, ma non viceversa.

    
risposta data 03.03.2016 - 13:32
fonte

Leggi altre domande sui tag