如何使用管道创建 json 漂亮的打印机
How to create json pretty printer with conduit
我正在学习 conduit
并想创建一个处理器,它可以从标准输入中获取 json 输入,以某种方式处理它,然后输出到标准输出。已经选择漂亮的印刷作为示例。
现在我只想解码 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
| ^^^^^^^^^^^^^^^^^^^^
bytestring
定义了严格类型(在 Data.ByteString
中)和惰性类型(在模块 Data.ByteString.Lazy
中)。修复您的代码可能就像导入 Data.ByteString.Char8
而不是惰性代码一样简单。如果库使用混合物,您可以使用 toStrict and fromStrict
进行转换
我正在学习 conduit
并想创建一个处理器,它可以从标准输入中获取 json 输入,以某种方式处理它,然后输出到标准输出。已经选择漂亮的印刷作为示例。
现在我只想解码 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
| ^^^^^^^^^^^^^^^^^^^^
bytestring
定义了严格类型(在 Data.ByteString
中)和惰性类型(在模块 Data.ByteString.Lazy
中)。修复您的代码可能就像导入 Data.ByteString.Char8
而不是惰性代码一样简单。如果库使用混合物,您可以使用 toStrict and fromStrict