Frage

Ich habe diese sehr einfache Funktion

import qualified Data.ByteString.Lazy as B

getJson :: IO B.ByteString
getJson = B.readFile jsonFile

readJFile :: IO (Maybe Response)
readJFile =  parsing >>= (\d ->
             case d of
                 Left err -> return Nothing
                 Right ps -> return (Just ps))
    where parsing = fmap eitherDecode getJson :: IO (Either String Response)

wo jsonFile ist ein Pfad zu einer Datei auf meiner Festplatte (verzeihen Sie das Fehlen der Do-Notation, aber ich fand es klarer damit zu arbeiten)

meine Frage ist;gibt es eine Möglichkeit für mich, die IO teil, damit ich alleine mit dem Bytestring arbeiten kann?

Ich weiß, dass Sie auf bestimmten Monaden wie Muster übereinstimmen können Either und Maybe um ihre Werte herauszuholen, aber kannst du etwas Ähnliches damit machen IO?

Oder anders geäußert:gibt es einen Weg für mich zu machen readJFile zurückgeben Maybe Response ohne das IO?

War es hilfreich?

Lösung

Um meine Kommentare zu erweitern, erfahren Sie hier, wie Sie es tun können:

getJson :: IO B.ByteString
getJson = B.readFile jsonFile -- as before

readJFile :: B.ByteString -> Maybe Response -- look, no IO
readJFile b = case eitherDecode b of
                Left err -> Nothing
                Right ps -> Just ps

Am Ende kombinierst du wieder alles in einer IO-Aktion:

getAndProcess :: IO (Maybe Response)
getAndProcess = do
  b <- getJson
  return (readJFile b)

Andere Tipps

Sie müssen niemals eine Monade durch irgendwelche Funktionen "ziehen", es sei denn, sie müssen alle tatsächlich IO ausführen.Heben Sie einfach die gesamte Kette mit in die Monade fmap (oder liftM / liftM2 / ...).

Beispielsweise,

f1 :: B.ByteString -> K
f2 :: K -> I
f3 :: K -> J
f4 :: I -> J -> M

und dein ganzes Ding soll so sein

m :: M
m = let k = "f1 getJson"
    in f4 (f2 k) (f3 k)

Das können Sie einfach tun

m = fmap (\b -> let k = f1 b
                in f4 (f2 k) (f3 k) )
    getJson

Das könnte übrigens schöner aussehen mit do Schreibweise:

m = do
  b <- getJson
  return $ let k = f1 b
           in f4 (f2 k) (f3 k)

Bezüglich deiner Bearbeitung und der Frage

gibt es einen Weg für mich zu machen readJFile zurückgeben Maybe Response ohne die IO?

Nein, das kann unmöglich funktionieren, weil readJFile muss IO machen.Es gibt keinen Weg, dem zu entkommen IO monade dann, das ist der springende Punkt!(Nun, es gibt unsafePerformIO wie Ricardo sagt, aber das ist definitiv keine gültige Bewerbung dafür.)

Wenn es die Klobigkeit des Auspackens ist Maybe werte in der IO monade und die Signaturen mit Parens in ihnen, vielleicht möchten Sie sich das ansehen MaybeT Transformator.

readJFile' :: MaybeT IO Response
readJFile' = do
   b <- liftIO getJson
   case eitherDecode b of
     Left err -> mzero
     Right ps -> return ps

Im Allgemeinen, ja, es gibt einen Weg.Begleitet von viel "aber", aber es gibt.Du fragst nach dem, was es heißt unsicherer IO-Betrieb: System.IO.Unsicher.Es wird normalerweise zum Schreiben von Wrappern beim Aufrufen externer Bibliotheken verwendet.Im regulären Haskell-Code kann darauf nicht zurückgegriffen werden.

Grundsätzlich können Sie anrufen unsafePerformIO :: IO a -> a was genau das macht, was Sie wollen, es streift die IO teil und gibt Ihnen den eingewickelten Wert des Typs zurück a.Wenn Sie sich jedoch die Dokumentation ansehen, gibt es eine Reihe von Anforderungen, die Sie selbst an das System stellen sollten, die alle auf die gleiche Idee führen:auch wenn Sie die Operation über E / A ausgeführt haben, sollte die Antwort das Ergebnis einer Funktion sein, wie von jeder anderen Haskell-Funktion erwartet, die nicht funktioniert IO:es sollte immer das gleiche Ergebnis ohne Nebenwirkungen haben, nur basierend auf den Eingabewerten.

Hier, gegeben Ihren Code, dies ist offensichtlich nicht der Fall, da Sie aus einer Datei lesen.Sie sollten einfach innerhalb der IO-Monade weiterarbeiten, indem Sie Ihre anrufen readJFile aus einer anderen Funktion mit Ergebnistyp IO something.Dann können Sie den Wert innerhalb des lesen IO wrapper (in sein IO selbst), arbeiten Sie daran und verpacken Sie das Ergebnis dann erneut in ein anderes IO bei der Rückkehr.

Nein, es gibt keinen sicheren Weg, um einen Wert aus der IO-Monade herauszuholen.Stattdessen sollten Sie die Arbeit innerhalb der E / A-Monade erledigen, indem Sie Funktionen mit fmap oder bind (>>=) anwenden.Außerdem sollten Sie decode anstelle von eitherDecode wenn Sie möchten, dass Ihr Ergebnis in Maybe .

getJson :: IO B.ByteString
getJson = B.readFile jsonFile

parseResponse :: B.ByteString -> Maybe Response
parseResponse = decode

readJFile :: IO (Maybe Response)
readJFile = fmap parseResponse getJSON

Sie könnten auch die do Notation verwenden, wenn Ihnen das klarer ist:

readJFile :: IO (Maybe Response)
readJFile = do
    bytestring <- getJson
    return $ decode bytestring

Beachten Sie, dass Sie die parseResponse Funktion nicht einmal benötigen, da readJFile den Typ angibt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top