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 .| sinkListsourceHandle に渡されたハンドルを 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
| ^^^^^^^^^^^^^