Perché Today () è un esempio di funzione impura?


38

Sembra che, quando leggono qualcosa di simile a questo articolo di Wikipedia sulle "funzioni pure" , elencano Today()come esempio di una funzione impura, ma mi sembra abbastanza puro. È perché non esiste un argomento di input formale? Perché l'ora effettiva del giorno non viene trattata come "input per la funzione", nel qual caso se gli hai dato lo stesso input, cioè eseguito today()due volte alla volta o se hai viaggiato indietro nel tempo per eseguirlo di nuovo (forse un ipotetico: )), l'uscita sarebbe la stessa ora. Today()non ti dà mai un numero casuale. ti dà sempre l'ora del giorno.

L'articolo di Wikipedia dice "tempi diversi produrrà risultati diversi" ma è come dire che per diversi x sin(x)ti darà rapporti diversi. Ed sin(x)è il loro esempio di pura funzione.


8
Se passassi all'ora del giorno, cosa farebbe la funzione?
JB King,

1
Mi aspetto che ti dia l'ora del giorno. (non la funzione più utile). Ma non ha alcun argomento, che penso sia la radice della risposta.
Brad

3
Puoi prevederne l'output (in base ai parametri di input forniti)?
Daniel B,

1
@DanielB Non esiste alcun potere predittivo per il parametro di input assente / nullo che risulta. L'unica cosa che posso fare è guardare il mio orologio da polso (jk il mio cellulare).
Brad

"Perché l'ora effettiva del giorno non viene trattata come" input per la funzione "" Questo è, fondamentalmente, il problema che le monadi cercano di risolvere. Le funzioni pure possono essere basate solo sui loro input e non possono avere effetti collaterali. Se rendi lo "stato del mondo davanti a me" un input e "lo stato del mondo dopo di me" parte del valore di ritorno e passi questi stati del mondo attraverso il tuo programma, puoi essere di nuovo puro.
Sean McSomething il

Risposte:


103

È perché non esiste un argomento di input formale?

È perché l'output dipende da qualcosa che non è un input, ovvero l'ora corrente.

Perché l'ora effettiva del giorno non viene trattata come "input per la funzione"

Perché non l'hai passato come parametro. Se lo passassi come parametro, la funzione diventerebbe una funzione di identità nelle date, il che è piuttosto inutile. L'intero punto di una Today()funzione è produrre qualcosa che dipende da un valore (tempo) esterno e in costante cambiamento.

Il vantaggio delle funzioni pure è che il loro comportamento è assolutamente riproducibile e deterministico, rendendo facile avere prove formali e garanzie concrete. Fanno sempre la stessa cosa. Today()è praticamente l'opposto: fa sempre (permettendo la granularità temporale) fa qualcosa di diverso.


2
Quindi, anche se il tempo della realtà è una sorta di input, perché non è dato come input ed è al di fuori del controllo della funzione (sia internamente alla funzione che al di fuori del controllo di chiunque sta chiamando Today()) Today()diventa impuro. La Today()funzione potrebbe essere un po 'un esempio sciocco. Più appropriata potrebbe essere una Count()funzione. Dato lo stesso numero di elementi da contare Count()restituirà sempre lo stesso numero, ma poiché questo è al di fuori dello scopo di Count()esso è impuro.
Brad

1
@brad è in qualche modo un'area grigia - c'è un argomento implicito reale - l'array o l'elenco. Dato un elenco immutabile e lo stesso argomento ogni volta restituirà sempre lo stesso valore.
Max

34
"il tempo della realtà è una specie di input" - sì; infatti, lo stato globale è implicitamente disponibile (cioè "una sorta di input") per tutte le funzioni, ma se dipendono da esso per il loro risultato sono impure!
AakashM,

4
@ Brad count()sulla maggior parte dei linguaggi di programmazione è sicuramente puro. Ha un valore di input esplicito: la raccolta di cui desideri il conteggio. Non essere confuso da una sintassi come myCollection.count(); questo è solo zucchero per count(myCollection).
Andres F.

Ottima risposta come sempre, ma non copre esplicitamente variabili libere immutabili. Non sono un input per la funzione - non passano come parametro - ma la funzione dipende da loro anche se è ancora referenzialmente trasparente.

24

sin(x)restituirà sempre lo stesso valore, purché xrimanga lo stesso. Today()potrebbe restituire risultati diversi nel tempo perché dipende da valori al di fuori del tuo controllo . Ad esempio, se qualcosa al di fuori del controllo del programma cambia l'interno del sistema $current_datetime mentre il programma è in esecuzione, Today()improvvisamente produrrà risultati diversi.


"restituirà sempre un valore diverso" è un po '... formulazione impura . Wikipedia dice "ritorna il giorno corrente della settimana", il che significa che i valori ottenuti il ​​lunedì non differiranno
moscerino del

7
@gnat: Vero, a meno che qualcosa di esterno al tuo programma non abbia cambiato il calendario interno del tuo computer in modo che improvvisamente pensasse che fosse giovedì. Quindi la chiamata Today()tornerebbe "giovedì" di lunedì.
FrustratedWithFormsDesigner,

3
@gnat Beh, non restituirà sempre un valore diverso (quasi nessuna funzione utile lo fa). Ma, come la maggior parte delle funzioni impure, il valore di ritorno può variare anche durante l'esecuzione di un singolo programma (ad esempio, se viene eseguito durante la notte).

3
@delnan: Sì, questa è la rovina degli ingenui autori di script di database! : P "Ma come potrebbero mancare 300 dischi? La sceneggiatura ha funzionato bene quando l'ho provata ieri mattina!"
FrustratedWithFormsDesigner,

@delnan questo è sicuro. Ho solo sottolineato che usare sempre nella formulazione iniziale (corretta nella risposta della versione attuale a could ) era in qualche modo impreciso
moscerino del

13

Today () è una funzione impura perché il suo risultato dipende da qualcosa che non gli dai; in particolare, l'ora corrente del sistema. Pertanto, il suo risultato non è deterministico se basato solo sugli input forniti all'invocazione.

Una pura funzione sarebbe int Add(int a, int b) {return a + b;}. La funzione funziona esclusivamente con ciò che viene fornito e non utilizza altri dati di stato esterni. Il risultato naturale di questo è che puoi Add(2,2)e ottenere 4 da ora fino alla fine dei tempi. Inoltre, poiché la funzione non cambia alcuno stato esterno (non ha "effetti collaterali"), Aggiungi () ing 2 e 2 da ora fino alla fine dei tempi non cambierà nient'altro nel sistema, a meno che tu assegnare il risultato della funzione a una variabile o utilizzare in altro modo il valore per aggiornare lo stato (che non è un'operazione eseguita dalla funzione stessa). Praticamente tutte le operazioni matematiche classiche sono funzioni pure e possono essere implementate come tali.

Today (), d'altra parte, può produrre lo stesso valore quando viene chiamato due volte di seguito, ma non se chiamato ripetutamente per diversi giorni. Questo perché dipende da dati di stato esterni che non vengono forniti dall'utente come parametro della funzione. Di conseguenza, è impossibile, entro i limiti del programma, controllare il risultato della funzione Today (). Produrrà un determinato valore in un determinato giorno e non produrrà mai quel valore in nessun altro giorno, a meno che non si modifichi l'orologio di sistema del computer su cui viene eseguito (una modifica che si verifica generalmente al di fuori dei limiti del programma).

Una funzione impura non è necessariamente una cosa negativa; sono necessarie funzioni impure, anche in linguaggi funzionali, per interagire con qualsiasi cosa al di fuori dei confini del programma, come archivi dati, condutture di comunicazione, display dell'interfaccia utente, dispositivi periferici, ecc. Un programma che non fa nulla di tutto ciò è un programma questo è fortemente limitato nella sua utilità; Andrei persino al punto di definire banale un programma del genere, poiché senza alcun mezzo per accettare input o vie per informarti del suo output, potrebbe anche non fare nulla. I programmi scritti in linguaggi funzionali possono avere solo l'input fornito dal runtime e produrre un output segnalato al runtime senza metodi impuri definiti in modo esplicito, ma questo perché il runtime sta sottraggendo tutti questi dettagli impuri del lavoro all'interno di un sistema informatico imperfetto,

È semplicemente una cosa molto buona sapere quali delle funzioni che stai usando sono pure e quali no, in modo da poter prendere delle buone decisioni su come vengono utilizzate. Le funzioni impure, poiché fanno cose o dipendono da cose che non sono evidenti dal loro uso, possono comportarsi in modo imprevedibile, data la sola conoscenza dell'uso. Sono necessarie ulteriori conoscenze sullo scopo della funzione, e quindi su ciò di cui ha bisogno da o verso uno stato esterno, al fine di posizionare un sistema che lo utilizza in uno stato coerente e quindi aspettarsi un risultato deterministico.


8

Sembra abbastanza ovvio che questa funzione non supera il primo test di purezza dato all'inizio di quella pagina:

  1. 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.

Si noti che poiché non accetta argomenti, esiste solo un possibile set di valori argomento: il set vuoto. E questa funzione può e restituisce risultati diversi per gli stessi "valori argomento".

Inoltre, il valore del risultato funzione non dipende "... stato nascosto che potrebbero variare con l'esecuzione procede programma". Quindi un altro fallimento.


@ JörgWMittag Non sono sicuro di dove sostengo che una funzione senza argomenti non può restituire un valore.
AakashM,

Lapsus. Ho letto "esiste solo un possibile insieme di valori di ritorno ".
Jörg W Mittag,

8

() => 1sarebbe una funzione pura, poiché restituisce sempre 1. Today()può restituire "lunedì" o "martedì" o quasi qualsiasi altro valore.

Un altro modo di pensarci è che le funzioni pure non dipendono dallo stato. Il mondo è generalmente considerato stato. Devi conoscere lo stato della realtà per sapere che giorno è oggi.

Tuttavia non hai bisogno di sapere nulla di speciale sullo stato del mondo per sapere cos'è sin(x). E mai chiamare sin(x)per un dato xrestituirà lo stesso valore.


Wikipedia dice "ritorna il giorno corrente della settimana", il che significa che può tornare lunedì, martedì ecc. Ma non "23/01/2013" né "24/01/2013"
moscerino

7
@gnat: aggiornato, ma la differenza non era davvero significativa.
Guvante,

2

Date(timestamp)sarebbe una pura funzione. A causa della sua idempotenza. E perché non ci sarebbero effetti collaterali.

Today()può variare il risultato a seconda di quando lo chiami. Questo è ciò che lo rende impuro. Non è idempotente. Tuttavia non ha effetti collaterali, ma ciò non lo rende puro.


2

Ecco un piccolo pseudo codice a cui penso quando parlo di funzioni pure

newValue = Function();
while(true)
{
   oldValue = newValue;
   newValue = Function();
   assert( newValue == oldValue );
}

Se funziona all'infinito e non può mai innescare l'asserzione, è una funzione pura. Inoltre, se hai una funzione che usa args, allora una piccola modifica ....

oldValue = Function( importantVariableToYourApp );
newValue = Function( importantVariableToYourApp );
assert( newValue == oldValue );

Se puoi usarlo dopo ogni assegnazione variabile nella tua app e non cambia i risultati nella tua app e non può mai fallire l'affermazione, allora è una pura funzione.


2

Innanzitutto, non esiste una funzione senza argomento (o una matrice senza indici o una mappa senza chiavi). È la caratteristica che definisce una funzione mappare uno o più valori di argomento su un altro valore.

Quindi, todayo non è affatto una funzione, quindi nessuna funzione pura. Oppure potremmo interpretare la sintassi

today()

un po 'in modo che significhi

today   ()      -- today, applied to the value ()

In Haskell, ad esempio, questo sarebbe valido:

data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun deriving Show
today :: () -> Day
today () = ....?
main = print (today())

perché esiste un tipo () con un singolo valore ().

La domanda è solo, come può todaycalcolare il giorno della settimana, se ha solo ()? Semplicemente non è possibile senza leggere il timer di sistema, direttamente o tramite le funzioni impure di aiuto.

Il timer di sistema è un eccellente esempio di stato globale.


1

Il problema today()è che può produrre un risultato diverso se chiamato due o più volte in una funzione.

Ecco un esempio di codice che potrebbe introdurre un bug.

function doSomething(when)
{
     if(today() == when)
     {
           // open a resource or create a temp file.....
     }

     // do some other work

     if(today() == when)
     {
           // close the resource or delete temp file.....
     }
}

È possibile nell'esempio sopra. Che la seconda ifistruzione non verrà eseguita. Anche se il primo lo ha fatto. Lasciando una risorsa in cattivo stato.


1

Per essere una funzione pura, fornire gli stessi parametri deve dare sempre lo stesso risultato.

Ogni volta che chiamiamo Today(), forniamo gli stessi parametri (nessuno) e non otteniamo necessariamente lo stesso risultato (lunedì, martedì, ecc.).


4
questo sembra semplicemente ripetere il punto sollevato e spiegato in una risposta importante che è stata pubblicata circa due anni fa. Difficilmente vale la pena rispondere a una domanda di due anni con un contenuto del genere
moscerino il

1
Non ho molta familiarità con il funzionamento di stackexchange, ma ho pensato che dato che questo era tra le domande principali era già stato superato. Per quanto riguarda il punto di ripetizione, ricordo di aver letto su meta che può essere utile avere più risposte simili. Sento che il mio è succinto e potenzialmente utile.
Zantier,
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.