我有一个yaml文件:
base123: key1: "key1" key2: "key2" key3: "key3"
和代码,它被允许从中读取所有3个值:
read123 :: IO (String, String, String) read123 = do rawConfig <- Y.decodeFile "config.yml" :: IO (Maybe Y.Value) case rawConfig of Just res1 -> case res1 of Object res2 -> case (LHashMap.lookup "base123" res2) of Just (Object res3) -> case (LHashMap.lookup "key1" res3) of Just (String key1) -> case (LHashMap.lookup "key2" res3) of Just (String key2) -> case (LHashMap.lookup "key3" res3) of Just (String key3) -> return (key1, key2, key3) _ -> error "some error" Nothing -> error "error123"
它似乎工作正常.但我相信,必须有一种方法可以在不使用Lens的情况下摆脱嵌套表达式.有没有?或者有什么方法可以更简单地做同样的事情?
更新:
rawConfig <- Y.decodeFile "config.yml" :: IO (Maybe Y.Value) case rawConfig of Just (Object res1) -> LHashMap.lookup "base123" res1 Nothing -> error "error" return ("", "", "") -- stub
错误:
Couldn't match type `Maybe' with `IO' Expected type: IO Value Actual type: Maybe Value In the return type of a call of `LHashMap.lookup'
Sibi.. 6
我建议您使用正确的数据类型来存储您的YAML数据.Michael Snoyman的yaml库重用了大部分API aeson
.所以它与你使用aeson包的方式非常相似.这是一个有效的示例代码:
{-# LANGUAGE OverloadedStrings #-} import Control.Applicative import Control.Monad (mzero) import Data.Text import Data.Yaml data Base = Base { key1 :: Text, key2 :: Text, key3 :: Text } deriving (Show) instance FromJSON Base where parseJSON (Object v) = Base <$> ((v .: "base123") >>= (.: "key1")) <*> ((v .: "base123") >>= (.: "key2")) <*> ((v .: "base123") >>= (.: "key3")) parseJSON _ = mzero main = do b <- decodeFile "/home/sibi/yaml.yml" :: IO (Maybe Base) print b
在ghci:
?> main Just (Base {key1 = "key1", key2 = "key2", key3 = "key3"})
Petr Pudlák.. 5
使用Maybe
monad 可以简化这一过程.
让我们专注于片段
case (LHashMap.lookup "base123" res2) of Just (Object res3) -> case (LHashMap.lookup "key1" res3) of Just (String key1) -> case (LHashMap.lookup "key2" res3) of Just (String key2) -> case (LHashMap.lookup "key3" res3) of Just (String key3) -> return (key1, key2, key3)
首先让我们定义提取器Object
和String
(我不知道你需要的确切类型,但这应该是显而易见的):
getString :: (MonadPlus m) => ... -> m String getString (String o) = return o getString _ = mzero getObject :: ... getObject (Object o) = return o getObject _ = mzero
现在可以用Maybe
monad中的计算替换代码段:
do -- in the Maybe moned res3 <- getObject =<< LHashMap.lookup "base123" res2 key1 <- getString =<< LHashMap.lookup "key1" res3 key2 <- getString =<< LHashMap.lookup "key2" res3 key3 <- getString =<< LHashMap.lookup "key2" res3 return (key1, key2, key3)
如果一切顺利,你会得到Just (...)
,否则Nothing
(你可以变成一个IO
错误).
旁白:请注意,嵌套case
表达式不会按预期工作,因为它们会形成不完整的模式.例如,如果您定义
test x y = case x of Just x' -> case y of Just y' -> True _ -> False
然后test (Just 0) Nothing
失败了.该_
模式仅适用于最外层case
,而不适用于内部模式.
此外,我建议从部分中拆分纯部分(在纯函数中处理数据)IO
.
我建议您使用正确的数据类型来存储您的YAML数据.Michael Snoyman的yaml库重用了大部分API aeson
.所以它与你使用aeson包的方式非常相似.这是一个有效的示例代码:
{-# LANGUAGE OverloadedStrings #-} import Control.Applicative import Control.Monad (mzero) import Data.Text import Data.Yaml data Base = Base { key1 :: Text, key2 :: Text, key3 :: Text } deriving (Show) instance FromJSON Base where parseJSON (Object v) = Base <$> ((v .: "base123") >>= (.: "key1")) <*> ((v .: "base123") >>= (.: "key2")) <*> ((v .: "base123") >>= (.: "key3")) parseJSON _ = mzero main = do b <- decodeFile "/home/sibi/yaml.yml" :: IO (Maybe Base) print b
在ghci:
?> main Just (Base {key1 = "key1", key2 = "key2", key3 = "key3"})
使用Maybe
monad 可以简化这一过程.
让我们专注于片段
case (LHashMap.lookup "base123" res2) of Just (Object res3) -> case (LHashMap.lookup "key1" res3) of Just (String key1) -> case (LHashMap.lookup "key2" res3) of Just (String key2) -> case (LHashMap.lookup "key3" res3) of Just (String key3) -> return (key1, key2, key3)
首先让我们定义提取器Object
和String
(我不知道你需要的确切类型,但这应该是显而易见的):
getString :: (MonadPlus m) => ... -> m String getString (String o) = return o getString _ = mzero getObject :: ... getObject (Object o) = return o getObject _ = mzero
现在可以用Maybe
monad中的计算替换代码段:
do -- in the Maybe moned res3 <- getObject =<< LHashMap.lookup "base123" res2 key1 <- getString =<< LHashMap.lookup "key1" res3 key2 <- getString =<< LHashMap.lookup "key2" res3 key3 <- getString =<< LHashMap.lookup "key2" res3 return (key1, key2, key3)
如果一切顺利,你会得到Just (...)
,否则Nothing
(你可以变成一个IO
错误).
旁白:请注意,嵌套case
表达式不会按预期工作,因为它们会形成不完整的模式.例如,如果您定义
test x y = case x of Just x' -> case y of Just y' -> True _ -> False
然后test (Just 0) Nothing
失败了.该_
模式仅适用于最外层case
,而不适用于内部模式.
此外,我建议从部分中拆分纯部分(在纯函数中处理数据)IO
.