In realtà è solo un normale costruttore di dati che sembra essere definito in Prelude , che è la libreria standard che viene importata automaticamente in ogni modulo.
Quello che forse è, strutturalmente
La definizione è simile a questa:
data Maybe a = Just a
| Nothing
Quella dichiarazione definisce un tipo, Maybe ache è parametrizzato da una variabile di tipo a, il che significa semplicemente che puoi usarlo con qualsiasi tipo al posto di a.
Costruire e distruggere
Il tipo ha due costruttori Just ae Nothing. Quando un tipo ha più costruttori, significa che un valore del tipo deve essere stato costruito con uno solo dei possibili costruttori. Per questo tipo, un valore è stato costruito tramite Justo Nothing, non ci sono altre possibilità (non di errore).
Poiché Nothingnon ha alcun tipo di parametro, quando viene utilizzato come costruttore nomina un valore costante che è un membro del tipo Maybe aper tutti i tipi a. Ma il Justcostruttore ha un parametro di tipo, il che significa che quando usato come costruttore si comporta come una funzione dal tipo aa Maybe a, cioè ha il tipoa -> Maybe a
Quindi, i costruttori di un tipo costruiscono un valore di quel tipo; l'altro lato delle cose è quando vorresti usare quel valore, ed è qui che entra in gioco il pattern matching. A differenza delle funzioni, i costruttori possono essere utilizzati nelle espressioni di associazione di modelli e questo è il modo in cui è possibile eseguire l' analisi dei casi dei valori che appartengono a tipi con più di un costruttore.
Per utilizzare un Maybe avalore in una corrispondenza di pattern, è necessario fornire un pattern per ogni costruttore, in questo modo:
case maybeVal of
Nothing -> "There is nothing!"
Just val -> "There is a value, and it is " ++ (show val)
In quel caso espressione, il primo modello corrisponderebbe se il valore fosse Nothing, e il secondo corrisponderebbe se il valore fosse costruito con Just. Se il secondo corrisponde, associa anche il nome valal parametro che è stato passato al Justcostruttore quando è stato costruito il valore con cui stai confrontando.
Che cosa significa forse
Forse conoscevi già come funzionava; non c'è davvero alcuna magia per i Maybevalori, è solo un normale Haskell Algebraic Data Type (ADT). Ma è usato un bel po 'perché effettivamente "solleva" o estende un tipo, come Integerdal tuo esempio, in un nuovo contesto in cui ha un valore extra ( Nothing) che rappresenta una mancanza di valore! Il sistema di tipi richiede quindi che tu controlli quel valore extra prima che ti permetta di arrivare a quello Integerche potrebbe essere lì. Ciò impedisce un numero notevole di bug.
Molte lingue oggi gestiscono questo tipo di valore "senza valore" tramite riferimenti NULL. Tony Hoare, un eminente scienziato informatico (ha inventato Quicksort ed è un vincitore del Turing Award), riconosce questo come il suo "errore da un miliardo di dollari" . Il tipo Forse non è l'unico modo per risolvere questo problema, ma ha dimostrato di essere un modo efficace per farlo.
Forse come Functor
L'idea di trasformare un tipo ad un altro in modo tale che le operazioni sul vecchio tipo possono anche essere trasformati in lavoro sul nuovo tipo è il concetto alla base della classe tipo Haskell chiamato Functor, che Maybe aha un esempio utile.
Functorfornisce un metodo chiamato fmap, che mappa le funzioni che vanno dai valori del tipo base (come Integer) a funzioni che vanno dai valori del tipo elevato (come Maybe Integer). Una funzione trasformata fmapper lavorare su un Maybevalore funziona così:
case maybeVal of
Nothing -> Nothing -- there is nothing, so just return Nothing
Just val -> Just (f val) -- there is a value, so apply the function to it
Quindi, se hai un Maybe Integervalore m_xe una Int -> Intfunzione f, puoi fmap f m_xapplicare la funzione fdirettamente a Maybe Integersenza preoccuparti se ha effettivamente un valore o meno. In effetti, potresti applicare un'intera catena di Integer -> Integerfunzioni elevate ai Maybe Integervalori e Nothingdevi preoccuparti di controllare esplicitamente una volta sola quando hai finito.
Forse come monade
Non sono sicuro di quanto tu abbia familiarità con il concetto di Monadancora, ma almeno l'hai usato IO aprima e la firma del tipo IO asembra notevolmente simile a Maybe a. Sebbene IOsia speciale in quanto non ti espone i suoi costruttori e può quindi essere "eseguito" solo dal sistema di runtime Haskell, è anche un Functoroltre ad essere un file Monad. In effetti, c'è un senso importante in cui a Monadè solo un tipo speciale Functorcon alcune funzionalità extra, ma non è questo il posto per entrare in questo.
Ad ogni modo, alle monadi piacciono i IOtipi di mappatura su nuovi tipi che rappresentano "calcoli che si traducono in valori" e puoi elevare le funzioni in Monadtipi tramite una fmapfunzione molto simile chiamata liftMche trasforma una funzione regolare in un "calcolo che risulta nel valore ottenuto valutando il funzione."
Probabilmente hai intuito (se hai letto fin qui) che Maybeè anche un file Monad. Rappresenta "calcoli che potrebbero non riuscire a restituire un valore". Proprio come fmapnell'esempio, questo ti consente di eseguire un sacco di calcoli senza dover controllare esplicitamente gli errori dopo ogni passaggio. In effetti, il modo in cui Monadviene costruita l' istanza, un calcolo sui Maybevalori si interrompe non appena Nothingsi incontra a, quindi è un po 'come un aborto immediato o un ritorno senza valore nel mezzo di un calcolo.
Potresti aver scritto forse
Come ho detto prima, non c'è nulla di inerente al Maybetipo che è integrato nella sintassi del linguaggio o nel sistema di runtime. Se Haskell non lo ha fornito per impostazione predefinita, potresti fornire tu stesso tutte le sue funzionalità! In effetti, potresti riscriverlo comunque tu stesso, con nomi diversi, e ottenere la stessa funzionalità.
Si spera che tu capisca il Maybetipo e i suoi costruttori ora, ma se c'è ancora qualcosa di poco chiaro, fammelo sapere!
Maybedove altre lingue userebberonullonil(con brutti messaggi inNullPointerExceptionagguato in ogni angolo). Ora anche altri linguaggi iniziano a usare questo costrutto: Scala asOption, e anche Java 8 avrà ilOptionaltipo.