constpotrebbe essere solo l'implementazione che stai cercando insieme ad altre funzioni. Ecco un esempio che ho scoperto.
Supponiamo di voler riscrivere una struttura di 2-tuple in un'altra struttura di 2-tuple. Potrei esprimere questo in questo modo:
((a,b),(c,d)) ⇒ (a,(c,(5,a)))
Posso dare una definizione semplice con il pattern matching:
f ((a,b),(c,d)) = (a,(c,(5,a)))
E se volessi una soluzione inutile (tacita) per questo tipo di riscritture? Pensando e giocherellando dopo, la risposta è che possiamo esprimere qualsiasi riscrittura con (&&&), const, (.), fst, snd. Nota che (&&&)è da Control.Arrow.
La soluzione dell'esempio che utilizza queste funzioni è:
(fst.fst &&& (fst.snd &&& (const 5 &&& fst.fst)))
Nota la somiglianza con (a,(c,(5,a))). E se sostituiamo &&&con ,? Quindi si legge:
(fst.fst, (fst.snd, (const 5, fst.fst)))
Nota come aè il primo elemento del primo elemento, e questo è ciò che fst.fstprogetti. Nota come cè il primo elemento del secondo elemento, e questo è ciò che fst.sndprogetti. Cioè, le variabili diventano il percorso verso la loro fonte.
constci permette di introdurre costanti. Interessante come il nome si allinea con il significato!
Ho poi generalizzato questa idea con applicativo in modo che si può scrivere qualsiasi funzione in uno stile inutile (finché si dispone di un'analisi caso disponibili come funzioni, ad esempio maybe, either, bool). Ancora una volta, constsvolge il ruolo di introdurre costanti. Puoi vedere questo lavoro nel pacchetto Data.Function.Tacit .
Quando inizi in modo astratto, all'obiettivo, e poi lavori verso un'implementazione, puoi essere sorpreso dalle risposte. Vale a dire, qualsiasi funzione può essere misteriosa come qualsiasi ingranaggio di una macchina. Tuttavia, se ti tiri indietro per visualizzare l'intera macchina, puoi capire il contesto in cui è necessario quell'ingranaggio.
backgroundColor :: Text -> Colorè per mebackgroundColor = const White