从 monad 到 IO monad - 简单且惯用的方式?
Either monad to IO monad - simple and idiomatic way?
此代码编译:
read :: IO Config
read = do
c1 <- BS.readFile "my_config.yaml"
case Y.decodeEither' c1 of
Right x -> pure x
Left e -> error "error 123"
哪里没有:
read :: IO Config
read = do
liftIO $ case (BS.readFile "my_config.yaml") >>= Y.decodeEither' of
Right x -> pure x
Left e -> error "error 123"
===>
Expected type: IO Config
Actual type: Either a1 Config
如何将 Either monad 转换为 IO one?我想要一种简单且惯用的方式,不需要额外的库。
行 BS.readFile "my_config.yaml" >>= Y.decodeEither'
没有多大意义,因为 decodeEither' :: FromJSON a => ByteString -> Either ParseException a
本身不是 return 一个 IO a
,并且 BS.readFile
不是一个 Either ParseException b
,所以它既没有 IO
单子上下文,也没有 Either a
单子上下文。
你可以做的是对结果执行仿函数映射,所以 Y.decodeEither' <$> BS.readFile "my_config.yaml"
,但是它的类型是 FromJSON a => IO (Either ParseException a)
,所以你不能使用 Left
的模式匹配和Right
。
但是您可以将其实现为:
read :: IO Config
read = do
result <- <b>Y.decodeEither <$></b> BS.readFile "my_config.yaml"
case <b>result</b> of
Right x -> pure x
Left e -> error e
或者您可以像 那样在 case
部分执行映射:
read :: IO Config
read = do
result <- BS.readFile "my_config.yaml"
case <b>Y.decodeEither result</b> of
Right x -> pure x
Left e -> error e
此处无需使用do
或liftIO
。
read :: IO Config
read = Y.decodeEither' <$> BS.readFile "my_config.yaml" >>= \c -> case c of
Right x -> pure x
Left e -> error "error 123"
应该做。
但是使用 ExceptT
transformer 可能会更好,那么您需要做的就是
read :: ExceptT ParseException IO Config
read = ExceptT $ Y.decodeEither <$> BS.readFile "my_config.yaml"
现在你可以像这样了;
configure :: ExceptT ParseException IO ()
configure = read >>= pure . processConfig
或如@Joseph Sible-Reinstate Monica 所提醒的那样
configure :: ExceptT ParseException IO ()
configure = processConfig <$> read
如果 decodeEither
returns 一个 Left
值,它会被记录并 processConfig :: Config -> ()
被跳过。
read :: IO Config
read = do
liftIO $ case (BS.readFile "my_config.yaml") >>= Y.decodeEither' of
Right x -> pure x
Left e -> error "error 123"
在上面的错误尝试中,它几乎看起来像你想要的 -XLambdaCase:
fmap Y.decodeEither' (BS.readFile "my_config.yaml) >>= \case
Right x -> pure x
Left e -> error "error 123"
但我发现 either
更具可读性:
either (error "error 123") pure . Y.decodeEither' =<< BS.readFile "my_config.yaml"
此代码编译:
read :: IO Config
read = do
c1 <- BS.readFile "my_config.yaml"
case Y.decodeEither' c1 of
Right x -> pure x
Left e -> error "error 123"
哪里没有:
read :: IO Config
read = do
liftIO $ case (BS.readFile "my_config.yaml") >>= Y.decodeEither' of
Right x -> pure x
Left e -> error "error 123"
===>
Expected type: IO Config
Actual type: Either a1 Config
如何将 Either monad 转换为 IO one?我想要一种简单且惯用的方式,不需要额外的库。
行 BS.readFile "my_config.yaml" >>= Y.decodeEither'
没有多大意义,因为 decodeEither' :: FromJSON a => ByteString -> Either ParseException a
本身不是 return 一个 IO a
,并且 BS.readFile
不是一个 Either ParseException b
,所以它既没有 IO
单子上下文,也没有 Either a
单子上下文。
你可以做的是对结果执行仿函数映射,所以 Y.decodeEither' <$> BS.readFile "my_config.yaml"
,但是它的类型是 FromJSON a => IO (Either ParseException a)
,所以你不能使用 Left
的模式匹配和Right
。
但是您可以将其实现为:
read :: IO Config
read = do
result <- <b>Y.decodeEither <$></b> BS.readFile "my_config.yaml"
case <b>result</b> of
Right x -> pure x
Left e -> error e
或者您可以像 case
部分执行映射:
read :: IO Config
read = do
result <- BS.readFile "my_config.yaml"
case <b>Y.decodeEither result</b> of
Right x -> pure x
Left e -> error e
此处无需使用do
或liftIO
。
read :: IO Config
read = Y.decodeEither' <$> BS.readFile "my_config.yaml" >>= \c -> case c of
Right x -> pure x
Left e -> error "error 123"
应该做。
但是使用 ExceptT
transformer 可能会更好,那么您需要做的就是
read :: ExceptT ParseException IO Config
read = ExceptT $ Y.decodeEither <$> BS.readFile "my_config.yaml"
现在你可以像这样了;
configure :: ExceptT ParseException IO ()
configure = read >>= pure . processConfig
或如@Joseph Sible-Reinstate Monica 所提醒的那样
configure :: ExceptT ParseException IO ()
configure = processConfig <$> read
如果 decodeEither
returns 一个 Left
值,它会被记录并 processConfig :: Config -> ()
被跳过。
read :: IO Config
read = do
liftIO $ case (BS.readFile "my_config.yaml") >>= Y.decodeEither' of
Right x -> pure x
Left e -> error "error 123"
在上面的错误尝试中,它几乎看起来像你想要的 -XLambdaCase:
fmap Y.decodeEither' (BS.readFile "my_config.yaml) >>= \case
Right x -> pure x
Left e -> error "error 123"
但我发现 either
更具可读性:
either (error "error 123") pure . Y.decodeEither' =<< BS.readFile "my_config.yaml"