如何用管道创建json漂亮的打印机

时间:2018-01-31 14:10:21

标签: haskell stream conduit

我正在学习conduit并希望创建一个处理器,它将从stdin中获取json输入,以某种方式处理它,然后输出到stdout。选择漂亮的印刷作为例子。

现在我想解码json并将其打印出来。但似乎我遇到了Bytestring类型不匹配的问题。

import Control.Monad.Trans.Resource
   import Data.Aeson
   import Data.Conduit
   import qualified Data.Conduit.Combinators as CC
   import Data.Conduit (await, yield, (.|))
   import Data.ByteString.Lazy.Char8 as BC
   import qualified Data.Conduit.Binary as CB
   import Data.JsonStream.Parser hiding ((.|))
   import qualified Data.Text as T
   import System.IO (stdin, stdout)


   jsonParse :: Conduit BC.ByteString IO (T.Text, Value)
   jsonParse = doParse parseOutput
     where
       parseOutput :: ParseOutput (T.Text, Value)
       parseOutput = runParser (objectItems value)

       doParse :: ParseOutput (T.Text, Value) -> Conduit BC.ByteString IO (T.Text, Value)
       doParse out = case out of
           ParseYield value newOutput -> do
               yield value
               doParse newOutput
           ParseNeedData cont ->
               awaitForever $ \i -> doParse (cont i)
           ParseDone remaining -> return ()
           ParseFailed err -> error err

   main = runConduit $ CB.sourceHandle stdin .| jsonParse .| CC.map (encode . snd) .| CB.sinkHandle stdout


   /tmp/some1/app/Main.hs:25:13: error:
       • Couldn't match type ‘Data.ByteString.Internal.ByteString’
                        with ‘ByteString’
         NB: ‘ByteString’ is defined in ‘Data.ByteString.Lazy.Internal’
             ‘Data.ByteString.Internal.ByteString’
               is defined in ‘Data.ByteString.Internal’
         Expected type: Conduit ByteString IO (T.Text, Value)
           Actual type: ConduitM
                          Data.ByteString.Internal.ByteString (T.Text, Value) IO ()
       • In the expression: awaitForever $ \ i -> doParse (cont i)
         In a case alternative:
             ParseNeedData cont -> awaitForever $ \ i -> doParse (cont i)
         In the expression:
           case out of
             ParseYield value newOutput
               -> do yield value
                     doParse newOutput
             ParseNeedData cont -> awaitForever $ \ i -> doParse (cont i)
             ParseDone remaining -> return ()
             ParseFailed err -> error err
      |
   25 | awaitForever $ \i -> doParse (cont i)
      | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

   /tmp/some1/app/Main.hs:25:34: error:
       • Couldn't match type ‘ByteString’
                        with ‘Data.ByteString.Internal.ByteString’
         NB: ‘Data.ByteString.Internal.ByteString’
               is defined in ‘Data.ByteString.Internal’
             ‘ByteString’ is defined in ‘Data.ByteString.Lazy.Internal’
         Expected type: ConduitM
                          Data.ByteString.Internal.ByteString (T.Text, Value) IO ()
           Actual type: Conduit ByteString IO (T.Text, Value)
       • In the expression: doParse (cont i)
         In the second argument of ‘($)’, namely ‘\ i -> doParse (cont i)’
         In the expression: awaitForever $ \ i -> doParse (cont i)
      |
   25 | awaitForever $ \i -> doParse (cont i)
      | ^^^^^^^^^^^^^^^^

   /tmp/some1/app/Main.hs:29:46: error:
       • Couldn't match type ‘ByteString’
                        with ‘Data.ByteString.Internal.ByteString’
         NB: ‘Data.ByteString.Internal.ByteString’
               is defined in ‘Data.ByteString.Internal’
             ‘ByteString’ is defined in ‘Data.ByteString.Lazy.Internal’
         Expected type: ConduitM
                          Data.ByteString.Internal.ByteString Data.Void.Void IO ()
           Actual type: ConduitM ByteString Data.Void.Void IO ()
       • In the second argument of ‘(.|)’, namely
           ‘jsonParse .| CC.map (encode . snd) .| CB.sinkHandle stdout’
         In the second argument of ‘($)’, namely
           ‘CB.sourceHandle stdin
              .| jsonParse .| CC.map (encode . snd) .| CB.sinkHandle stdout’
         In the expression:
           runConduit
             $ CB.sourceHandle stdin
                 .| jsonParse .| CC.map (encode . snd) .| CB.sinkHandle stdout
      |
   29 | main = runConduit $ CB.sourceHandle stdin .| jsonParse .| CC.map (encode . snd) .| CB.sinkHandle stdout
      | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

   /tmp/some1/app/Main.hs:29:84: error:
       • Couldn't match type ‘Data.ByteString.Internal.ByteString’
                        with ‘ByteString’
         NB: ‘ByteString’ is defined in ‘Data.ByteString.Lazy.Internal’
             ‘Data.ByteString.Internal.ByteString’
               is defined in ‘Data.ByteString.Internal’
         Expected type: ConduitM ByteString Data.Void.Void IO ()
           Actual type: ConduitM
                          Data.ByteString.Internal.ByteString Data.Void.Void IO ()
       • In the second argument of ‘(.|)’, namely ‘CB.sinkHandle stdout’
         In the second argument of ‘(.|)’, namely
           ‘CC.map (encode . snd) .| CB.sinkHandle stdout’
         In the second argument of ‘(.|)’, namely
           ‘jsonParse .| CC.map (encode . snd) .| CB.sinkHandle stdout’
      |
   29 | main = runConduit $ CB.sourceHandle stdin .| jsonParse .| CC.map (encode . snd) .| CB.sinkHandle stdout
      | ^^^^^^^^^^^^^^^^^^^^

1 个答案:

答案 0 :(得分:1)

bytestring定义了严格类型(Data.ByteString)&懒惰类型(在模块Data.ByteString.Lazy中)。修复代码可能就像导入Data.ByteString.Char8而不是惰性代码一样简单。如果库使用混合物,您可以使用toStrictfromStrict

进行转换