Pergunta

Eu tenho isso muito simples função

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)

onde jsonFile é um caminho para um arquivo no disco rígido (perdoem a falta do que fazer de notação, mas eu achei isso mais claro para trabalhar com)

a minha pergunta é;há para mim uma forma de abandonar o IO peça para que eu possa trabalhar com o bytestring sozinho?

Eu sei que você pode correspondência de padrão em determinados campos como Either e Maybe para obter os seus valores, mas você pode fazer algo semelhante com IO?

Ou expressaram de forma diferente:existe uma maneira de me fazer readJFile retorno Maybe Response sem o IO?

Foi útil?

Solução

Para expandir os meus comentários, aqui está como você pode fazer isso:

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

No final, depois de combinar tudo em um IO ação novamente:

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

Outras dicas

Você nunca precisa para "arrastar uma mônada" através de quaisquer funções, a menos que todos eles precisam realmente fazer IO.Apenas levante a toda a cadeia para a mônada com fmap (ou liftM / liftM2 / ...).

Por exemplo,

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

e toda a sua coisa é suposto para ser como

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

O que você pode simplesmente fazer

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

Aliás, isso pode parecer mais agradável com do notação:

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

Sobre você editar e a questão

existe uma maneira de me fazer readJFile retorno Maybe Response sem o IO?

Nenhum, que não pode trabalhar, porque readJFile não precisa fazer IO.Não há nenhuma maneira de escapar dos IO mônada em seguida, que é o ponto de todo ele!(Bem, não há unsafePerformIO como o Ricardo diz, mas este definitivamente não é um aplicativo válido para ele.)

Se é o clunkiness de descompactar Maybe valores em IO mônada, e as assinaturas com parens neles, você pode querer olha para o MaybeT transformador.

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

Em geral, sim, há um caminho.Acompanhado por um monte de "mas", mas não é.Você está pedindo para o que é chamado de inseguro operação de e / s: Do sistema.IO.Inseguro.Ele é usado para escrever mensagens publicitárias ao chamar a bibliotecas externas, geralmente, não é algo que recorrer a regular Haskell código.

Basicamente, você pode chamar unsafePerformIO :: IO a -> a o que faz exatamente o que você quer, ele retira o IO parte e dá-lhe de volta envolto valor do tipo a.Mas, se você olhar para a documentação, há uma série de requisitos que você deve garantir-se ao sistema, o que na mesma idéia:mesmo que você executou a operação através de IO, a resposta deve ser o resultado de uma função, como esperado de qualquer outro haskell função que não operam no IO:ele deve ter sempre o mesmo resultado, sem efeitos colaterais, apenas com base nos valores de entrada.

Aqui, dado o seu código, isso obviamente NÃO é o caso, já que você está lendo de um arquivo.Você deve apenas continuar a trabalhar no IO mônada, chamando seu readJFile de dentro de outra função com o tipo de resultado IO something.Em seguida, você vai ser capaz de ler o valor no IO wrapper (sendo em IO si mesmo), trabalhar nele e, em seguida, re-moldar o resultado em outro IO quando voltar.

Não, não há nenhuma forma segura de obter um valor de IO mônada.Em vez disso, você deve fazer o trabalho dentro do IO mônada pela aplicação de funções com fmap ou ligar (>>=).Além disso, você deve usar decodificar em vez de eitherDecode quando você deseja que o seu resultado seja Talvez.

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

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

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

Você também pode usar o fazer notação se que é mais clara para você:

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

Note que você não precisa mesmo de o parseResponse função desde readJFile especifica o tipo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top