Dopo aver letto (e sfogliato alcune sezioni di) il lavoro di Wadler sulle monadi, ho deciso di lavorare più a fondo sul foglio, definendo il funtore e le istanze applicative per ciascuna delle monadi che descrive. Utilizzando il tipo sinonimoFunctor/istanze applicative per stato in Haskell
type M a = State -> (a, State)
type State = Int
Wadler utilizza per definire la monade stato, ho i seguenti (nomi correlati che utilizzano in modo che possa definirli con una dichiarazione newtype in seguito).
fmap' :: (a -> b) -> M a -> M b
fmap' f m = \st -> let (a, s) = m st in (f a, s)
pure' :: a -> M a
pure' a = \st -> (a, st)
(<@>) :: M (a -> b) -> M a -> M b
sf <@> sv = \st -> let (f, st1) = sf st
(a, st2) = sv st1
in (f a, st2)
return' :: a -> M a
return' a = pure' a
bind :: M a -> (a -> M b) -> M b
m `bind` f = \st -> let (a, st1) = m st
(b, st2) = f a st1
in (b, st2)
Quando si passa ad usare un costruttore di tipo in una dichiarazione newtype, ad esempio,
newtype S a = S (State -> (a, State))
tutto crolla. Tutto è solo una leggera modifica, per esempio,
instance Functor S where
fmap f (S m) = S (\st -> let (a, s) = m st in (f a, s))
instance Applicative S where
pure a = S (\st -> (a, st))
tuttavia nulla viene eseguito in GHC a causa del fatto che l'espressione lambda è nascosto all'interno di quel tipo di costruzione. Ora l'unica soluzione che vedo è quello di definire una funzione:
isntThisAnnoying s (S m) = m s
allo scopo di impegnare s per 'st' ed effettivamente restituire un valore, ad esempio,
fmap f m = S (\st -> let (a, s) = isntThisAnnoying st m in (f a, s))
c'è un altro modo per fare questo che non usa queste funzioni ausiliarie?
Che significa anche 'runState = flip isntThisAnnoying'. – kennytm
OK - così mentre è ancora necessaria una funzione ausiliaria, potrei semplicemente definire il tipo usando un record, ottenendo la funzione gratuitamente. Quello che stai dicendo, quindi, è che non c'è modo di evitare l'uso di funzioni come "runState" o "run". Grazie. – danportin
Se ti fa male pensarlo come una funzione, pensa invece ad esso come un accessore di campo struct. :-) –