Domanda

Ho questa funzione molto semplice

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)
.

Dove jsonFile è un percorso verso un file sul mio harddrive (perdonare la mancanza di notazione, ma ho trovato questo più chiaro con)

La mia domanda è;C'è un modo per me di abbandonare la parte IO, quindi posso lavorare con il bytestring da solo?

So che puoi modellare la partita su alcune monadi come Either e Maybe per ottenere i loro valori, ma puoi fare qualcosa di simile con IO?

o espresso in modo diverso: c'è un modo per me per rendere readJFile Return Maybe Response senza IO?

È stato utile?

Soluzione

Per espandere i miei commenti, ecco come puoi farlo:

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
.

Alla fine, si combina di nuovo tutto in un'azione IO:

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

Altri suggerimenti

Non hai mai bisogno di "trascinare una monada" attraverso qualsiasi funzione, a meno che non siano tutte dotate di fare in realtà. Sollevare l'intera catena nella monaca con fmap (o liftM / liftM2 / ...).

Ad esempio,

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

E la tua intera cosa dovrebbe essere come

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

La tua puoi semplicemente fare

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

Per inciso, questo potrebbe sembrare più bello con la notazione do:

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


.

riguardo a modifica e la domanda

.

C'è un modo per farmi guadagnare readJFile Maybe Response senza il IO?

no , che non può funzionare, perché readJFile ha bisogno di fare IO. Non c'è modo di sfuggire al IO Monad allora, questo è l'intero punto di questo! (Bene, c'è unsafePerformIO come dice Ricardo, ma questa è sicuramente una domanda valida per questo.)

Se è la stregazza del disimballaggio dei valori generacoli Maybe nella monade IO, e le firme con parente in esse, potresti voler guardare a Trasformatore MaybeT .

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

In generale, sì, c'è un modo. Accompagnato da un sacco di "ma", ma c'è. Stai chiedendo cosa si chiama un'operazione non sicura IO : system.io.unsafe . È usato per scrivere involucri quando si chiama di solito alle librerie esterne, non è qualcosa da ricorrere al normale codice Haskell.

Fondamentalmente, è possibile chiamare unsafePerformIO :: IO a -> a che fa esattamente quello che desideri, si spoglia la parte IO e ti restituisce il valore avvolto del tipo a. Ma se guardi la documentazione, ci sono una serie di requisiti che dovresti garantirti al sistema, che finiscono tutti nella stessa idea: anche se hai eseguito l'operazione tramite IO, la risposta dovrebbe essere il risultato di a Funzione, come previsto da qualsiasi altra funzione Haskell che non funziona in IO: dovrebbe sempre avere lo stesso risultato senza effetti collaterali, in base ai valori di input.

Qui, dato il tuo codice, questo ovviamente non è il caso , dal momento che stai leggendo da un file. Dovresti continuare a lavorare all'interno dell'Io Monad, chiamando il tuo readJFile da un'altra funzione con il tipo di risultato IO something. Quindi, sarai in grado di leggere il valore all'interno del wrapper IO (essendo in IO da solo), lavora su di esso, quindi riavvolgere il risultato in un altro IO quando si ritorna.

No, there is no safe way to get a value out of the IO monad. Instead you should do the work inside the IO monad by applying functions with fmap or bind (>>=). Also you should use decode instead of eitherDecode when you want your result to be 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

You could also use do notation if that is clearer to you:

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

Note that you dont even need the parseResponse function since readJFile specifies the type.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top