Calcola se una funzione è pura


11

Secondo Wikipedia:

Nella programmazione al computer, una funzione può essere descritta come pura se entrambe queste affermazioni sulla funzione sono valide: la funzione valuta sempre lo stesso valore di risultato dati gli stessi valori di argomento. Il valore del risultato della funzione non può dipendere da alcuna informazione o stato nascosto che può cambiare man mano che procede l'esecuzione del programma o tra diverse esecuzioni del programma, né può dipendere da alcun input esterno dai dispositivi I / O. La valutazione del risultato non provoca alcun effetto collaterale o output osservabile semanticamente, come la mutazione di oggetti mutabili o l'output a dispositivi I / O.

Mi chiedo se è possibile scrivere una funzione che calcoli se una funzione è pura o no. Codice di esempio in Javascript:

function sum(a,b) {
    return a+b;
}

function say(x){
    console.log(x);
}

isPure(sum) // True
isPure(say) // False

7
Potrebbe essere candidato per lo scambio di stack di informatica . Questo tende più al regno della teoria ("possibile") piuttosto che alla pratica e al design ... È un po 'oltre la mia comprensione.

... e anche se è "possibile" e "teoria", è molto probabile che vi sia una vera risposta (una buona misura per le domande e risposte) che potrebbe anche implicare una prova ... che la riporta ancora nel mondo dell'informatica .

Penso che sia possibile determinare se una funzione è pura osservando il tipo di funzioni che vengono invocate nella sua definizione. Voglio dire, puoi definire la purezza per induzione sulla struttura delle funzioni.
Giorgio,

7
Non è possibile fare a meno degli hack di riflessione specifici della piattaforma. Se una funzione è una scatola nera, nessun esperimento può dimostrare che è pura. Ad esempio, se esiste qualcosa di simile if (rand(1000000)<2) return WRONG_ANSWER, sondare la funzione più volte per un comportamento coerente non aiuta. Ma, se hai accesso alla definizione della funzione, la prova è banale.
SK-logic,

1
@ user470365 Dalla definizione di una funzione pura - "La valutazione del risultato non provoca alcun effetto collaterale o output osservabile semanticamente, come la mutazione di oggetti mutabili o l'output a dispositivi I / O." - Tutto ciò che scrive su IO è impuro per definizione. Nell'esempio, anche le saychiamate console.logche sono impure saysono pure impure.

Risposte:


17

Sì, è possibile, a seconda della lingua.

In JavaScript, puoi sapere se una funzione è pura secondo i seguenti criteri:

  • Legge solo parametri e locali;

  • Scrive solo gente del posto;

  • Sui non locali, chiama solo funzioni pure;

  • Tutte le funzioni che chiama implicitamente sono pure, ad esempio toString; e

  • Scrive le proprietà dei locali solo se non alias i non locali.

Aliasing non è possibile determinare in JavaScript nel caso generale, poiché è sempre possibile cercare dinamicamente le proprietà di un oggetto ( object["property"]). Se non lo fai mai e hai la fonte dell'intero programma, penso che il problema sia trattabile. Avresti anche bisogno di informazioni su quali funzioni native hanno effetti collaterali, come console.logo quasi tutto ciò che coinvolge il DOM.

Il termine "puro" potrebbe anche usare alcuni chiarimenti. Anche in un linguaggio di programmazione fortemente tipicamente statico e puramente funzionale, in cui tutte le funzioni sono referenzialmente trasparenti, una funzione può ancora non riuscire a terminare. Quindi, quando parliamo id :: a -> a, ciò che stiamo davvero dicendo non è:

Dato un valore di tipo a, la funzione idproduce un valore di tipo a.

Ma piuttosto:

Dato un valore di tipo a, la funzione idnon non produce un valore che è non di tipo a.

Perché un'implementazione valida di idè error "Not implemented!". Come sottolinea Peteris, questa non totalità potrebbe essere vista come una sorta di impurità. Koka è un linguaggio di programmazione funzionale — con sintassi modellata su JavaScript — che può inferire possibili effetti come divergenza (non termine), trasparenza referenziale, lancio di eccezioni e azioni I / O.


+1 - Data la risposta di Peteris ha ricevuto così tanti voti .....
mattnz il

Suppongo che dovresti aggiungere "Richiama solo funzioni pure" all'elenco dei criteri.
Greg Hewgill,

1
@GregHewgill: buona cattura. Ho aggiornato la risposta di conseguenza. Va bene chiamare funzioni mutanti sui locali, a condizione che non siano altrimenti efficaci. "Puro" è un termine troppo sovraccarico ...
Jon Purdy,

Devi anche verificare se toStringè puro per qualsiasi oggetto che usi come stringa.
Oleg V. Volkov,

Non penso che questa risposta sia corretta, perché ci sono solo un sottoinsieme di circostanze in cui è possibile effettuare queste determinazioni. Considera: questa funzione è pura? function a (o) { return o.method(); }- in realtà non possiamo rispondere, perché dipende dal parametro opassato. Inoltre, non possiamo tenere conto di ciò che accade se una funzione pura precedentemente certificata viene modificata in un'implementazione non pura, che è sempre un potenziale problema con javascript.
Jules,

11

No. Puoi facilmente verificare se una funzione esegue solo operazioni "pure-safe", come descritto nella risposta di Jon Purdy, ma questo non è abbastanza IMO per rispondere alla domanda.

Considera questa funzione:

function possiblyPure(x) {
    if (someCheck(x)) {
        return x+1; // pure code path
    }
    else {
        console.log("I'm so unpure..."); // unpure code path
    }
}

Ovviamente, se someCheckè impuro, lo è anche possiblyPure. Ma, se someCheckè puro e restituisce trueper ogni possibile valore di x, possiblyPureè puro, poiché il percorso del codice non puro è irraggiungibile!

E qui arriva la parte difficile: determinare se someCheckritorna vero per ogni possibile input. Cercare di rispondere a questa domanda immensamente ti porta nel regno del problema di arresto e simili problemi indecidibili.

EDIT: prova che è impossibile

C'è qualche incertezza se una funzione pura deve terminare su ogni possibile input. Ma in entrambi i casi, il problema dell'arresto può essere usato per dimostrare che il controllo di purezza è impossibile.

Caso A) Se è necessaria una funzione pura per terminare su ogni possibile input, è necessario risolvere il problema di arresto per determinare se la funzione è pura. Poiché ciò è noto per essere impossibile, con questa definizione, la purezza non può essere calcolata.

Caso B) Se una funzione pura non può terminare su alcuni input, possiamo costruire qualcosa del genere: supponiamo che isPure(f)calcoli se fè una stringa che definisce una funzione pura.

function halts(f) {
   var fescaped = f.replace(/\"/g, '\\"');
   var upf = 'function() { '+f+'("'+fescaped+'\); console.log("unpure"); }';
   return isPure(upf);
}

Ora isPuredeve determinare se si fferma o meno sulla propria fonte come input. Se si ferma, upfè impuro; se non termina, upfè puro se fè puro.

Se isPurefunzionasse come previsto (restituisce risultati corretti e termina con ogni input), avremmo risolto il problema di arresto (*)! Poiché questo è noto per essere impossibile, isPurenon può esistere.

(*) per funzioni JavaScript pure, che è sufficiente per risolverlo anche per il turing machine.


3
Vero. È sempre possibile fare un'analisi conservativa - per verificare se una funzione è sicuramente pura, ma non è possibile verificare se non è assolutamente pura.
SK-logic,

Molti casi sono banalmente decidibili: quelle pure funzioni descritte da Jon Purdy o funzioni non pure che incondizionatamente fanno qualcosa di sporco; ma in generale, si possono costruire casi indecidibili.
user281377

1

Questa domanda StackOverflow ha una risposta di yfeldblum che è rilevante qui. (E ha un downvote per qualche motivo che non riesco a capire. Sarebbe una cattiva etichetta a votare qualcosa che ha 3 anni?) Fornisce una prova che se una funzione è pura è riducibile al problema di arresto in un commento.

Penso che dal punto di vista pratico non sarebbe troppo difficile per alcune lingue se si lascia che la funzione ritorni sì, no o forse. Stavo guardando un video su Clojure un paio di giorni fa e l'oratore aveva fatto un conteggio di casi di impurità in una base di codice cercando circa 4 stringhe diverse (come "ref"). A causa dell'enfasi di Clojure sulla purezza e sulla segregazione delle cose impure, era banale, ma non era esattamente quello che stai cercando.

Quindi, teoricamente impossibile, praticamente possibile se modifichi un po 'la domanda, e penso che quanto sarebbe difficile dipenderebbe molto dal linguaggio. Linguaggi più semplici / più puliti, con particolare attenzione all'immutabilità e una buona riflessione, sarebbero più facili.


Immagino che fosse stato retrocesso perché è sbagliato. bottomè un valore valido di prima classe, non merita di essere discriminato in questo modo.
SK-logic,

0

Ottima domanda

Il meglio che puoi fare in pratica, non assumendo alcuna capacità di ascoltare le azioni di I / o per chiamare la funzione il più volte possibile. Quindi verifica se il valore restituito è coerente.

Ma non puoi farlo in generale. Probabilmente, i programmi non-stop sono non-puri e non possiamo decidere il problema.


1
-1: Sarebbe estremamente banale scrivere una funzione che superi questo test ed è tutt'altro che pura.
mattnz,

3
Secondo questa logica, qualsiasi voidfunzione sarebbe "pura", il che è chiaramente falso.
Greg Hewgill,

1
@Greg: per estensione, anche il vuoto (vuoto) dovrebbe essere puro.
mattnz,

0

Non è possibile nel caso generale. Vedi problema di arresto . In breve, è impossibile scrivere un programma che, dato una funzione e un input arbitrari, determina se il programma si arresterà o funzionerà per sempre. Se funziona per sempre, non è una funzione pura che si adatta alla definizione che hai dato.


5
Correre per sempre non sembra scartare una funzione dall'adattare i suoi criteri per una funzione pura.
whatsisname

+1: È implicito che la funzione termina con "La funzione valuta sempre lo stesso valore di risultato dato ...."
mattnz

2
Correre costantemente per sempre senza modificare alcuno stato è perfettamente "puro". Ma, ovviamente, è un problema terminologico qui.
SK-logic,

@mattnz, tale funzione valuterà sempre il bottomvalore.
SK-logic,

1
Riesco a vedere da dove viene il problema della terminologia. In alcune interpretazioni, una funzione "pura" è deterministica e non comunica mai alcuno stato o valore con l'esterno durante la sua esecuzione. In altre interpretazioni, l'arresto è aggiunto ai requisiti. Con la prima interpretazione, è facile determinare se una funzione è pura: una macchina che esegue un determinato linguaggio dovrebbe essere in grado di determinare se un programma in quel linguaggio comunica con l'esterno.
rwong
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.