Per dirla semplicemente, le restrizioni significano che ci sono meno modi corretti per mettere insieme le cose, e le funzioni di prima classe rendono più facile fattorizzare cose come le strutture ad anello. Prendi il ciclo da questa risposta , ad esempio:
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String string = iterator.next();
if (string.isEmpty()) {
iterator.remove();
}
}
Questo sembra essere l'unico modo imperativo sicuro in Java per rimuovere un elemento da una raccolta mentre lo stai ripetendo. Ci sono molti modi che sembrano molto vicini, ma sono sbagliati. Le persone ignare di questo metodo a volte passano attraverso modi contorti per evitare il problema, come invece scorrere una copia.
Non è terribilmente difficile rendere questo generico, quindi funzionerà su più di semplici raccolte di Strings, ma senza funzioni di prima classe, non è possibile sostituire il predicato (la condizione all'interno di if), quindi questo codice tende a essere copiato e incollato e leggermente modificato.
Combina funzioni di prima classe che ti danno la possibilità di passare il predicato come parametro, con la restrizione dell'immutabilità che lo rende molto fastidioso se non lo fai, e ti vengono in mente semplici blocchi come filter, come in questo codice Scala quello fa la stessa cosa:
list filter (!_.isEmpty)
Ora pensa a ciò che il sistema di tipi controlla per te, al momento della compilazione nel caso di Scala, ma questi controlli vengono eseguiti anche dai sistemi di tipi dinamici la prima volta che lo esegui:
listdeve essere una sorta di tipo che supporta il filtermetodo, vale a dire un insieme.
- Gli elementi di
listdevono avere un isEmptymetodo che restituisce un valore booleano.
- L'output sarà una raccolta (potenzialmente) più piccola con lo stesso tipo di elementi.
Una volta verificate queste cose, quali altri modi sono rimasti per il programmatore da rovinare? Ho dimenticato accidentalmente il !, che ha causato un errore del test case estremamente evidente. Questo è praticamente l'unico errore disponibile da fare, e l'ho fatto solo perché stavo traducendo direttamente dal codice testato per la condizione inversa.
Questo modello viene ripetuto più volte. Le funzioni di prima classe ti consentono di trasformare le cose in piccole utility riutilizzabili con una semantica precisa, restrizioni come l'immutabilità ti danno l'impulso di farlo e il controllo dei tipi di tali utility lascia poco spazio per rovinarle.
Naturalmente, tutto dipende dal fatto che il programmatore sappia che la funzione di semplificazione come filtergià esiste e che sia in grado di trovarla o di riconoscere il vantaggio di crearne una da soli. Prova a implementarlo da solo ovunque usando solo la ricorsione della coda e sei di nuovo nella stessa barca di complessità della versione imperativa, solo peggio. Solo perché puoi scriverlo in modo molto semplice, non significa che la versione semplice sia ovvia.