Questo non può essere fatto genericamente su tutte le istanze MonadIO
a causa del tipo IO
in una posizione negativa. Ci sono alcune librerie su hackage che fanno questo per istanze specifiche (monad-control,), ma c'è stato qualche dibattito sul fatto che siano semanticamente valide, specialmente per quanto riguarda il modo in cui gestiscono le eccezioni e le strane cose simili IO
.
Modifica: alcune persone sembrano interessate alla distinzione posizione positiva/negativa. In realtà, non c'è molto da dire (e probabilmente lo hai già sentito, ma con un nome diverso). La terminologia viene dal mondo dei sottotitoli.
L'intuizione dietro sottotipaggio è che "a
è un sottotipo di b
(che io scriverò a <= b
) quando un a
può essere utilizzato ovunque un b
ci si aspettava, invece". Decidere la sottotipizzazione è semplice in molti casi; per i prodotti, (a1, a2) <= (b1, b2)
ogni volta che a1 <= b1
e a2 <= b2
, ad esempio, è una regola molto semplice. Ma ci sono alcuni casi complicati; per esempio, quando dovremmo decidere che a1 -> a2 <= b1 -> b2
?
Bene, abbiamo una funzione f :: a1 -> a2
e un contesto prevede una funzione di tipo b1 -> b2
. Quindi il contesto utilizzerà il valore di ritorno di f
come se fosse un b2
, quindi è necessario che sia a2 <= b2
. La cosa delicata è che il contesto fornirà f
con un b1
, anche se lo f
lo userà come se fosse uno a1
. Quindi, dobbiamo richiedere che sia b1 <= a1
- che guarda all'indietro da ciò che potresti indovinare! Diciamo che a2
e b2
sono "covarianti" o si verificano in una "posizione positiva" e a1
e b1
sono "controvarianti" o si verificano in una "posizione negativa".
(Quick parte: perché? "Positivo" e "negativo" E 'motivato dalla moltiplicazione Prendere in considerazione questi due tipi:.
f1 :: ((a1 -> b1) -> c1) -> (d1 -> e1)
f2 :: ((a2 -> b2) -> c2) -> (d2 -> e2)
Quando dovrebbe f1
'tipo s essere un sottotipo di f2
' di tipo s io? dichiarare questi fatti (esercizio: controllare questo utilizzando la regola di cui sopra):
- dovremmo avere
e1 <= e2
- dovremmo avere
d2 <= d1
01.235.164,106 mila..
- Dovremmo avere
c2 <= c1
.
- Dovremmo avere
b1 <= b2
.
- Dovremmo avere
a2 <= a1
.
e1
è in una posizione positiva in d1 -> e1
, che è a sua volta in una posizione positiva nel tipo di f1
; inoltre, e1
è in una posizione positiva nel tipo di f1
in generale (poiché è covariante, per il fatto sopra). La sua posizione nell'intero termine è il prodotto della sua posizione in ogni sottotema: positivo * positivo = positivo. Allo stesso modo, d1
si trova in una posizione negativa in d1 -> e1
, che si trova in una posizione positiva nell'intero tipo. negativo * positivo = negativo e le variabili d
sono effettivamente controvarianti. b1
è in una posizione positiva nel tipo a1 -> b1
, che è in una posizione negativa in (a1 -> b1) -> c1
, che è in una posizione negativa nell'intero tipo. positivo * negativo * negativo = positivo, ed è covariante. Si ottiene l'idea)
Ora, diamo uno sguardo alla classe di MonadIO
:.
class Monad m => MonadIO m where
liftIO :: IO a -> m a
Possiamo vedere questo come una dichiarazione esplicita di sottotipo: stiamo dando un modo per fare IO a
essere un sottotipo di m a
per un po 'di cemento m
. Sappiamo subito che possiamo prendere qualsiasi valore con i costruttori IO
in posizioni positive e trasformarli in m
s. Ma questo è tutto: non abbiamo modo di trasformare i costruttori IO
negativi in m
s - abbiamo bisogno di una classe più interessante per questo.
Gah! perché tutte le domande di Haskell sono così difficili? Nessun punto facile qui :-( – drozzy
@drozzy: questo tag in realtà [ha uno dei più alti numeri medi di voti per risposta] (http://data.stackexchange.com/stackoverflow/query/61353/tags-with-highest-average -answer-scores-between-tags-with-at-least-1000-questions), quindi mentre potrebbero non essere sempre facili, le persone vengono premiate per i loro sforzi – hammar