Haskell Verwirrung mit ContT, callcc, wenn
-
19-09-2019 - |
Frage
Weiter Quest Sinn ContT und Freunde zu machen. Bitte beachten Sie den (absurd, aber zur Veranschaulichung) Code unten:
v :: IO (Either String [String])
v = return $ Left "Error message"
doit :: IO (Either String ())
doit = (flip runContT return) $ callCC $ \k -> do
x <- liftIO $ v
x2 <- either (k . Left) return x
when True $ k (Left "Error message 2")
-- k (Left "Error message 3")
return $ Right () -- success
Dieser Code nicht kompiliert. Wenn jedoch der die when
mit dem kommentierten k Anruf darunter ersetzen, es kompiliert. Was ist los?
Alternativ kann, wenn ich die x2 Zeile aus kommentieren, es kompiliert auch. ???
Offensichtlich ist dies eine destillierte Version des Original-Code und so alle Elemente dienen einem Zweck. Schätzen erklärend Hilfe auf, was los ist und wie man es beheben. Danke.
Lösung
Das Problem hat mit der Art des when
und either
, nicht etwas Besonderes zu ContT zu tun:
when :: forall (m :: * -> *). (Monad m) => Bool -> m () -> m ()
either :: forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
Das zweite Argument muß vom Typ m ()
für einige Monade m
sein. Die when
Zeile des Codes so wie so geändert werden:
when True $ k (Left "Error message 2") >> return ()
Kompilieren Sie den Code zu machen. Dies ist wahrscheinlich nicht das, was Sie tun wollen, aber es gibt uns einen Hinweis darüber, was könnte falsch sein. k
den Typ abgeleitet wurde etwas ungenießbar when
sein
Jetzt für die either
Unterschrift: bemerken, dass die beiden Argumente either
Funktionen, die Ergebnisse des gleichen Typs zu produzieren sein. Die Art der return
hier wird durch die Art der x
bestimmt, die durch die explizite Unterschrift auf v
fixiert wiederum ist. Somit muss das (k . Left)
Bit denselben Typ haben; Dies wiederum legt die Art der k
bei (GHC bestimmt)
k :: Either String () -> ContT (Either String ()) IO [String]
Dies ist unvereinbar mit when
Erwartungen.
Wenn Sie die x2
Zeile aus kommentieren, aber seine Wirkung auf die Ansicht der Typprüfer des Codes entfernt wird, so k
wird nicht mehr in eine unbequeme Art gezwungen und ist frei, um die Art zu übernehmen
k :: Either [Char] () -> ContT (Either [Char] ()) IO ()
, das ist in when
Buch in Ordnung. Somit stellt der Code.
Als abschließende Bemerkung, benutzte ich GHCi der Stützpunkte Einrichtung die genauen Arten von k
unter den beiden Szenarien zu erhalten - ich lange nicht Experte genug bin, um sie mit der Hand zu schreiben, und in keiner Weise von ihrer Richtigkeit gewährleistet sein. :-) Verwenden Sie :break ModuleName line-number column-number
, um es auszuprobieren.