"Nulla viene valutato finché non è necessario in un altro luogo" è una metafora semplificata che non copre tutti gli aspetti della valutazione pigra (ad esempio non menziona i fenomeni di rigidità).
Dal punto di vista teorico, ci sono 3 modi per andare quando si progetta un linguaggio puro (ovviamente se si basa su un qualche tipo di calcolo lambda e non su modelli di valutazione più esotici): rigoroso, non rigoroso e totale.
Ognuno di questi ha i suoi vantaggi e svantaggi, quindi è necessario leggere i documenti di ricerca corrispondenti.
Le lingue totali sono la più pura delle tre. Negli altri due la non-terminazione può essere vista come un effetto collaterale, quindi gli analizzatori di rigore e di totalità devono essere costruiti per mantenere efficiente un'implementazione. Entrambe le analisi sono indecidibili, quindi gli analizzatori non possono mai essere completi.
Tuttavia, le lingue totali sono meno espressive: è impossibile completare una lingua per Turing totale. Un approccio frequente per ottenere una buona espressività è di avere un sistema di prove integrato per una ricorsione fondata, che non è molto più facile da costruire rispetto agli analizzatori per le lingue non totali.
Dal punto di vista pratico, la semantica non rigida consente di definire più facilmente le astrazioni di controllo, poiché le strutture di controllo sono essenzialmente non rigide. In un linguaggio rigoroso hai ancora bisogno di alcuni posti con una semantica non rigida. Per esempio. Il costrutto if
ha una semantica non rigida anche in lingue rigorose.
Quindi, se la tua lingua è severa, le strutture di controllo sono un caso speciale. Al contrario, un linguaggio non rigoroso può essere uniformemente non severo - non ha un bisogno intrinseco in costrutti rigorosi.
Per quanto riguarda "chi scrive quel dieci volte prima di pranzo", chiunque usi Haskell per i loro progetti. Penso che sviluppare un progetto non giocattolo usando una lingua (una lingua non severa nel tuo caso) sia il modo migliore per coglierne i vantaggi e gli svantaggi.
seguito sono riportati alcuni casi d'uso generiche per pigrizia illustrati da esempi non-giocattolo:
Casi in cui il flusso di controllo è difficile da prevedere. Pensa alle grammatiche degli attributi quando, senza la pigrizia, devi eseguire un ordinamento topologico sugli attributi per risolvere le dipendenze. Riordinare il codice ogni volta che viene modificato il grafico delle dipendenze non è pratico. In Haskell è possibile implementare il formalismo grammaticale degli attributi senza un ordinamento esplicito e ci sono almeno due implementazioni effettive su Hackage. Le grammatiche degli attributi hanno un'ampia applicazione nella costruzione del compilatore.
L'approccio "genera e cerca" per risolvere molti problemi di ottimizzazione. In un linguaggio rigoroso devi interlacciare generazione e ricerca, in Haskell devi solo comporre funzioni di generazione e ricerca separate, e il tuo codice rimane sintatticamente modulare, ma intercalato in runtime. Pensa al problema del commesso viaggiatore (TSP), quando generi tutti i tour possibili e poi li analizzi utilizzando un algoritmo branch-and-bound. Si noti che il ramo di un algoritmo associato ispeziona solo alcune prime città di un tour, solo le parti necessarie dei percorsi sono generate. Il TSP ha diverse applicazioni anche nella sua formulazione più pura, come la pianificazione, la logistica e la produzione di microchip. Leggermente modificato, appare come un sotto-problema in molte aree, come il sequenziamento del DNA.
Il codice pigro ha un flusso di controllo non modulare, quindi una singola funzione può avere molti flussi di controllo possibili a seconda dell'ambiente in cui viene eseguita. Questo fenomeno può essere visto come una sorta di "polimorfismo del flusso di controllo", quindi controllo pigro le astrazioni di flusso sono più generiche delle loro controparti rigorose e una libreria standard di funzioni di ordine superiore è molto più utile in un linguaggio pigro. Pensa a generatori, loop ed elenchi iteratori Python: le funzioni dell'elenco Haskell coprono tutti e tre i casi, con il flusso di controllo che si adatta a diversi scenari di utilizzo a causa della pigrizia. Non si limita alle liste: si pensi a Data.Arrow e iteratees, versioni pigre e rigorose della monade di stato, ecc. Si noti inoltre che il flusso di controllo non modulare è sia un vantaggio che uno svantaggio, poiché rende più difficile ragionare sulle prestazioni.
Le strutture di dati probabilmente infiniti sono utili oltre gli esempi di giocattoli. Vedi i lavori di Conal Elliott sulla memoizzazione delle funzioni di ordine superiore usando i tentativi. Strutture di dati infiniti appaiono come spazi di ricerca infiniti (vedi 2), loop infiniti e generatori mai estenuanti in senso pitone (vedi 3).
Questo è un argomento interessante, ma lo si sta chiedendo in un modo piuttosto sfortunato, in sostanza richiedendo un grabbag di tutti gli scenari in cui qualcuno potrebbe immaginare che la valutazione pigra sia utile. Se stai progettando una lingua, faresti bene a concentrarti sulle decisioni specifiche che stai cercando di fare e chiedere assistenza nel valutare le opzioni in modo da poter fare scelte consapevoli. – Shog9
Non so se otterrete buone risposte qui, questa domanda è più utile per la programmazione di progettisti di linguaggi che per i programmatori. È il tipo di domanda per cui un [sito sull'informatica] (http://area51.stackexchange.com/proposals/35636/computer-science-non-programming?referrer=4M74nqLafvszXN85c5ibxQ2) funzionerebbe meglio. Raccomando gli articoli [citati su Wikipedia] (http://en.wikipedia.org/wiki/Lazy_evaluation#Further_reading) (non l'articolo WP stesso), in particolare "Perché FP è importante". – Gilles
rwallace: basato sulla modifica di @Gilles, ho modificato ulteriormente per enfatizzare la pigrizia della domanda come una funzione incorporata (con esempi usati per illustrare piuttosto che esempi come l'obiettivo finale), e riaperta sul presupposto che questo è accettabile Se non sei d'accordo, ti preghiamo di discutere. – Shog9