質問

私はこの非常に単純な機能を持っています

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)

ここで jsonFile 私のハードドライブ上のファイルへのパスです(do記法の欠如を許していますが、これはより明確に動作することがわかりました)

私の質問は;私が捨てる方法はありますか IO 私はbytestringだけで作業できるようにするための部分ですか?

私はあなたが特定のモナドでパターンマッチをすることができることを知っています EitherMaybe それらの値を取得するには、しかし、あなたは似たようなことをすることができますか IO?

または異なって声を出しました:私が作る方法はありますか readJFile 戻る Maybe Response IOなしで?

役に立ちましたか?

解決

私のコメントを展開するには、次のような方法があります。

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
.

最後に、1つのIOアクション内のすべてを再び結合します。

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

他のヒント

すべてが実際にIOを実行する必要がない限り、関数を介して"モナドをドラッグ"する必要はありません。チェーン全体をモナドに持ち上げるだけです fmap (または liftM / liftM2 / ...).

例えば,

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

そして、あなたの全体のことは次のようになるはずです

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

あなたは単に行うことができます

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

ちなみに、これはより良く見えるかもしれません do 表記法:

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

あなたの編集と質問について

私が作る方法はありますか readJFile 戻る Maybe Response せずに IO?

いいえ。, 、それはおそらく動作することはできませんので、 readJFile IOを行う必要があります。そこから逃げる方法はありません IO モナドそれから、それはそれの全体のポイントです!(まあ、あります unsafePerformIO リカルドが言うように、しかし、これは間違いなくそれのための有効なアプリケーションではありません。)

それは開梱のclunkinessだ場合 Maybe の値は、 IO モナド、およびそれらの中に括弧を持つ署名は、あなたが見てしたいことがあります MaybeT トランスフォーマー.

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

一般的に、はい、方法があります。たくさんの「しかし」を伴うが、あります。 Unsafe IO操作 system.io.unsafe 。外部ライブラリを呼び出すときにラッパーを書くのに使用されていますが、通常は通常のHaskellコードでリゾートするものではありません。

基本的には、必要なものを正確に行うunsafePerformIO :: IO a -> aを呼び出すことができます.IOパートを除外し、a型のバック値を戻します。しかし、あなたがドキュメントを見るならば、あなたがシステムにあなた自身を保証する必要がある多くの要件があります。これはすべて同じアイデアで終わった:あなたがIOを介して操作を行っても、答えはIOで動作していない他のHaskell関数から期待される関数は、入力値に基づいて副作用なしに同じ結果が常に同じ結果を持つべきです。

ここでは、あなたのコードを考えると、ファイルから読んでいるので、これは明らかにではありません。結果タイプのreadJFileを使用して、他の関数内からIO somethingを呼び出して、IOモナド内で作業するだけです。その後、IOラッパー内の値(IOが自分自身にある)で読むことができるようになり、復帰時に結果を別のIOに再描くことができます。

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.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top