Pregunta

Tengo esta función muy sencilla

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)

donde jsonFile es una ruta a un archivo en mi disco duro (perdón por la falta de notación, pero he encontrado esto más claro a trabajar)

mi pregunta es;hay una manera para mí para deshacerse de la IO parte para que yo pueda trabajar con el bytestring solo?

Yo sé que usted puede patrón coincide en ciertos mónadas como Either y Maybe para obtener sus valores, pero se puede hacer algo similar con IO?

O expresado de manera diferente:hay una manera para mí para hacer readJFile volver Maybe Response sin el IO?

¿Fue útil?

Solución

Para ampliar mis comentarios, aquí es cómo puedes hacerlo:

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

Al final, combinas todo en una acción de IO nuevamente:

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

Otros consejos

Usted nunca necesita "arrastrar una mónada" a través de cualquiera de las funciones, a menos que todos ellos necesitan para hacer realidad IO.Simplemente levante el conjunto de la cadena en la mónada con fmap (o liftM / liftM2 / ...).

Por ejemplo,

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

y toda su cosa se supone que para ser como

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

Usted puede simplemente hacer

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

Por cierto, esto podría ser más agradable con do notación:

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

Sobre la edición y la pregunta

hay una manera para mí para hacer readJFile volver Maybe Response sin el IO?

No, que no puede trabajar, porque readJFile no es necesario hacer IO.No hay manera de escapar de la IO mónada entonces, que es el punto entero de esto!(Bueno, hay unsafePerformIO como dice Ricardo, pero este definitivamente no es una aplicación válida para ello.)

Si es el clunkiness de desembalaje Maybe los valores en la IO mónada, y las firmas con paréntesis en ellos, usted puede querer que se ve en la MaybeT transformador.

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

En general, sí, hay una manera.Acompañado por una gran cantidad de "pero", pero no es.Estás pidiendo lo que se llama un inseguro operación de e / s: Sistema.IO.Inseguro.Se utiliza para escribir contenedores cuando se llama a bibliotecas externas generalmente, no es algo que recurrir a regular Haskell código.

Básicamente, usted puede llamar a unsafePerformIO :: IO a -> a que hace exactamente lo que usted desea, elimina la IO parte y le da la espalda envuelto valor de tipo a.Pero, si se mira en la documentación, hay una serie de requisitos que debe garantizarse a sí mismo en el sistema, que todos terminan en la misma idea:incluso a pesar de que se realizó la operación a través de IO, la respuesta debería ser el resultado de una función, como se espera de cualquier otra función haskell que no opera en IO:debe tener siempre el mismo resultado sin efectos secundarios, que sólo se basa en los valores de entrada.

Aquí, dado su código, obviamente, esto NO es el caso, ya que usted está leyendo desde un archivo.Usted debe seguir trabajando dentro de la mónada IO, llamando a su readJFile desde dentro de otra función con el tipo de resultado IO something.A continuación, podrás leer el valor en el IO contenedor (está en IO usted mismo), trabajar en él y, a continuación, vuelva a envolver el resultado en otra IO cuando regresan.

No, No hay ninguna forma segura de obtener un valor de la mónada IO.En lugar usted debe hacer el trabajo en el interior de la mónada IO mediante la aplicación de funciones con fmap o bind (>>=).También debe utilizar decodificar en lugar de eitherDecode cuando usted quiere que su resultado sea tal vez.

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

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

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

Usted podría también hacer uso de la notación si que es claro para usted:

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

Tenga en cuenta que usted no necesita de la parseResponse función desde readJFile especifica el tipo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top