Il Optional
di Java equivale essenzialmente alla% monade di hashell% co_de, quindi è un buon punto di partenza per capire come si comportano questi "valori avvolti".
Maybe
, Functors
e Applicatives
sono modi per modellare un tipo di comportamento aggiuntivo che può modificare un tipo esistente. Monads
prende un tipo e lo modifica in modo che possa modellare sia una una singola istanza o nessuna istanza di quel tipo. Maybe
modifica un tipo in modo tale da modellare una sequenza di istanze del tipo specificato.
Ciascuno di questi typeclass fornisce un modo per applicare una determinata funzione al tipo avvolto, rispettando le modifiche apportate dal tipo di wrapping. Ad esempio, in Haskell,
Funtori
I Functional usano le funzioni List
o fmap
(nomi diversi per la stessa cosa):
Questo prende una funzione e si applica agli elementi spostati
fmap (\x -> x + 1) (Just 1) -- Applies (+1) to the inner value, returning (Just 2)
fmap (\x -> x + 1) Nothing -- Applies (+1) to an empty wrapper, returning Nothing
fmap (\x -> x + 1) [1, 2, 3] -- Applies (+1) to all inner values, returning [2, 3, 4]
(\x -> x + 1) <$> [1, 2, 3] -- Same as above
applicativi
I candidati usano la funzione Functor f => (a -> b) -> f a -> f b
:
Questo richiede una funzione wrapped e la applica agli elementi spostati
(Just (\x -> x + 1)) <*> (Just 1) -- Returns (Just 2)
(Just (\x -> x + 1)) <*> Nothing -- Returns Nothing
Nothing <*> (Just 1) -- Returns Nothing
[(*2), (*4)] <*> [1, 2] -- Returns [2, 4, 4, 8]
Monadi
Ci sono due funzioni rilevanti nella classe di caratteri Monad:
-
Applicative f => f (a -> b) -> f a -> f b
return
-
Monad m => a -> m a
(>>=)
(pronunciato "bind")
La funzione Monad m => m a -> (a -> m b) -> m b
non ha alcuna somiglianza con quella che potresti avere familiarità con i linguaggi in stile C. Prende un valore raw e non compresso e lo avvolge nel tipo monadico desiderato.
makeJust :: a -> Maybe a
makeJust x = return x
let foo = makeJust 10 -- returns (Just 10)
La funzione bind consente di scartare temporaneamente gli elementi interni di una Monade e passarli a una funzione che esegue un'azione che li avvolge di nuovo nella stessa monade. Questo può essere usato con la funzione return
in casi banali:
[1, 2, 3, 4] >>= (\x -> return (x + 1)) -- Returns [2, 3, 4, 5]
(Just 1) >>= (\x -> return (x + 1)) -- Returns (Just 2)
Nothing >>= (\x -> return (x + 1)) -- Returns Nothing
Il punto in cui diventa interessante è quando si hanno delle funzioni da concatenare che non richiedono l'utilizzo di return
. Mi piace usare return
e getLine
come esempi, che hanno le seguenti firme che usano% mon_putStrLn
:
-
IO
getLine
-
IO String
putStrLn
Puoi chiamare queste funzioni in questo modo:
getLine >>= (\x -> putStrLn x) -- Gets a line from IO and prints it to the console
getLine >>= putStrLn -- With currying, this is the same as above
Potresti anche utilizzare la funzione String -> IO ()
per concatenare alcune operazioni insieme.
-- Reads a line from IO, converts to a number, adds 10 and prints it
getLine >>= (return . read) >>= (return . (+10)) >>= putStrLn . show