logLevel
定数のありかが気になってました。Orphan instance: instance From Word8 HogeSerializeFormat
という警告が出てしまいます。{-# OPTIONS_GHC -fno-warn-orphans #-}
をつければ警告を消せるようなのですが、そもそもこの警告は何が問題なのでしょうか?(実行時にエラーになる場合があるなど)instance From Word8 HogeSerializeFormat
の部分のファイルを分ければよいということが書いてあったのですが、分けようとした(module Data.Word内に書いてみた)際に循環importになってしまいビルドができなくなってしまいました。{-# OPTIONS_GHC -fno-warn-orphans #-}
をつけて警告を消してしまってよいのか、それとも別の方法がよいのか。{-# OPTIONS_GHC -fno-warn-orphans #-}
をつければ警告を消せるようなのですが、そもそもこの警告は何が問題なのでしょうか?
instance From HogeSerializeFormat Word8
Word8
という型の定義と、 From
という型クラスの定義、どちらのモジュールとも異なるモジュールで宣言しているから Orphan instance
と言われてしまいます。Word8
について From
のインスタンスがあることを知っていても、 Word8
が定義されたモジュール、 From
が定義されたモジュール、どちらを import してもインスタンスが利用できないため、使おうとしたときに迷ってしまう恐れがあるのです。instance From HogeSerializeFormat Word8
などを Data.From
モジュールに移動させれば、Data.From
に移動すればよかったのですね!conduitGet2
を真似して(ほぼコピペ)デシリアライズした値と一緒に、今何バイト目にいるのかをタプルで返すコードを書いてみたのですがコンパイルエラーになってしまいうまく行きません。i <- IO.hTell h
の部分を i <- return 123
などにするとコンパイルはできたのですが、なぜ i <- IO.hTell h
だとエラーになってしまうのかがわからない状況です。conduitGet3
などを定義せず既存の conduitGet2
を使いつつ今何バイト目にいるのかをデシリアライズした値と一緒に返す方法なんてあったりするのでしょうか?• Couldn't match type ‘IO’ with ‘ConduitT BS.ByteString (o, Integer) m’ Expected type: ConduitT BS.ByteString (o, Integer) m Integer Actual type: IO Integer • In a stmt of a 'do' block: i <- IO.hTell h In the expression: do i <- IO.hTell h yield (x, i) if BS.null rest then awaitNE >>= start else start rest In an equation for ‘result’: result (Done x rest) = do i <- IO.hTell h yield (x, i) if BS.null rest then awaitNE >>= start else start rest • Relevant bindings include x :: o (bound at app/Main.hs:73:18) result :: Result o -> ConduitT BS.ByteString (o, Integer) m () (bound at app/Main.hs:66:5) awaitNE :: forall o. ConduitT BS.ByteString o m BS.ByteString (bound at app/Main.hs:54:5) g :: Get o (bound at app/Main.hs:49:15) conduitGet3 :: IO.Handle -> Get o -> ConduitT BS.ByteString (o, Integer) m () (bound at app/Main.hs:49:1) | 74 | i <- IO.hTell h | ^^^^^^^^^^
IO.hTell h
は IO Integer
型になりますが result :: Data.Serialize.Result o -> ConduitT BS.ByteString (o, Integer) m ()
型になるため, do
構文の制約により ConduitT BS.ByteString (o, Integer) m
モナドでなく IO
モナドを使っているためエラーになります. return 123
にするとうまくいくのは, return 123 :: ConduitT BS.ByteString (o, Integer) m Integer
となるためです.result :: _ -> _
とすればエラーメッセージとして表示されるようになります.runConduit $ sourceHandle h .| conduitGet3 h .| sinkList
sourceHandle
に渡されたハンドルを conduitGet3
にも渡される前提で使用するという想定で合ってますか?runConduit $ CC.sourceHandle h .| conduitGet3 h (get :: Get Value.Value) .| CC.mapM_ print
で画面に表示されるか試していました!conduitGet3 :: MonadThrow m => Get o -> ConduitT BS.ByteString (o, Int) m () conduitGet3 g = conduitGet2 (twoOf g bytesRead)
twoOf
という関数をググっても出てこないのですがこれはどこで定義されている関数でしょうか?conduitGet3
を修正する場合, http://hackage.haskell.org/package/base-4.11.1.0/docs/Control-Monad-IO-Class.html を使用して hTell h
の部分を liftIO (hTell h)
にすれば動くはずです.• Could not deduce (MonadIO m) arising from a use of ‘liftIO’ from the context: MonadThrow m bound by the type signature for: conduitGet3 :: forall (m :: * -> *) o. MonadThrow m => IO.Handle -> Get o -> ConduitT BS.ByteString (o, Integer) m () at app/Main.hs:49:1-93 Possible fix: add (MonadIO m) to the context of the type signature for: conduitGet3 :: forall (m :: * -> *) o. MonadThrow m => IO.Handle -> Get o -> ConduitT BS.ByteString (o, Integer) m () • In a stmt of a 'do' block: i <- liftIO (IO.hTell h) In the expression: do i <- liftIO (IO.hTell h) yield (x, i) if BS.null rest then awaitNE >>= start else start rest In an equation for ‘result’: result (Done x rest) = do i <- liftIO (IO.hTell h) yield (x, i) if BS.null rest then awaitNE >>= start else start rest | 75 | i <- liftIO (IO.hTell h) | ^^^^^^^^^^^^^^^^^^^
conduitGet3 :: (MonadThrow m, MonadIO m) => IO.Handle -> Get o -> ConduitT BS.ByteString (o, Integer) m ()
にしたらビルドできました!(Nil,3) (Bool True,3) (Bool False,3)
(Nil,0) (Bool True,1) (Bool False,2)
echo -en "\x00\x01\x02"
で作成したファイルを読ませていて、0x00がNil、0x01がBool True、0x02がBool FalseとなっておりますconduitGet2
を流用するのは無理なんじゃないかなと思いますね.やるとしたらConduitに新しいAPIを足さなきゃいけない気がします(echo -en "\x00\x01\x02\x08\x01"
こんな感じで \x08\x01
の2つで UInt8 1
のようなデータもあるんです…conduitGet4 :: MonadThrow m => Get o -> ConduitT BS.ByteString (o, Int) m () conduitGet4 g = conduitGet2 ((,) <$> g <*> bytesRead) .| conduitPosFix 0 where conduitPosFix !p = await >>= \case Nothing -> pure () Just (x, l) -> do yield (x, p) conduitPosFix $ p + l
error: parse error on input ‘case’ | 84 | conduitPosFix !p = await >>= \case |
-XLambdaCase
が必要なんですね!失礼しました!Variable not in scope: conduitPosFix :: Integer -> ConduitM (o, Int) (o, Int) m () | 82 | conduitGet4 g = conduitGet2 ((,) <$> g <*> bytesRead) .| conduitPosFix 0 | ^^^^^^^^^^^^^