我正在尝试从以下代码中获取Config数据记录:
data Connections = Connections { cfgProperty :: !Object
, connectionName :: String
} deriving (Show, Generic)
data Config = Config {connections :: [Connections]} deriving (Show, Generic)
data Cfg = Cfg { config :: Config } deriving (Show, Generic)
instance FromJSON Cfg
instance FromJSON Config
instance FromJSON Connections
instance ToJSON Cfg
instance ToJSON Config
instance ToJSON Connections
jsonFile :: FilePath
jsonFile = "config/config.json"
getCfg :: IO B.ByteString
getCfg = B.readFile jsonFile
parseCfg = do
j <- (A.eitherDecode <$> getCfg) :: IO (Either String Cfg)
case j of
Left err -> liftIO $ putStrLn err
Right j -> config j
我收到以下错误:
/apps/workspace/hade/src/Actor/MasterActor.hs: 56, 20
• Couldn't match expected type ‘IO ()’ with actual type ‘Config’
• In the expression: config j
In a case alternative: Right j -> config j
In a stmt of a 'do' block:
case j of {
Left err -> liftIO $ putStrLn err
Right j -> config j }
这是config.json
{
"config":
{
"connections": [
{
"cfgProperty":
{
"Env": "local",
"Host": "localhost",
"Port": "8001",
"Directory": "/apps/workspace/hade/maps/src01_cvs"
},
"connectionName": "src01_cvs"
},
{
"cfgProperty":
{
"Env": "local",
"Host": "localhost",
"Port": "8001",
"Directory": "/apps/workspace/hade/maps/trg01_cvs"
},
"connectionName": "trg01_cvs"
}
]
}
}{
"config":
{
"connections": [
{
"cfgProperty":
{
"Env": "local",
"Host": "localhost",
"Port": "8001",
"Directory": "/apps/workspace/hade/maps/src01_cvs"
},
"connectionName": "src01_cvs"
},
{
"cfgProperty":
{
"Env": "local",
"Host": "localhost",
"Port": "8001",
"Directory": "/apps/workspace/hade/maps/trg01_cvs"
},
"connectionName": "trg01_cvs"
}
]
}
}
我已经使用Decode和decode尝试了许多不同的配置,但每次都遇到了障碍。如果我将案例更改为:
,我可以获取打印出Config记录的代码 case j of
Left err -> putStrLn err
Right j -> print $ config j
(以及其他一些更改),但我无法简单地返回Config记录本身。任何帮助将不胜感激。
答案 0 :(得分:1)
您遇到的问题的根源是getCfg
中对parseCfg
的调用。 getCfg
的类型是IO ByteString
,它是IO
monad,你可以用IO
monad做的唯一事情是调用必须为所有人定义的函数monads(bind
,fmap
,ap
,...)所有这些都会返回另一个IO
monad。这意味着如果parseCfg
要调用getCfg
,那么必须返回IO
monad。
引用haskell wiki:“因为你无法从IO monad中逃脱,所以不可能编写一个在IO monad中进行计算但其结果类型不包含{{1类型构造函数。“
解决此问题的一种方法是在IO
之外拨打getCfg
并将结果传递给parseCfg
。然后parseCfg
可以返回parseCfg
但返回Config
更有意义,以便保留Either String Config
的任何解析错误。这样,您就可以将eitherDecode
定义为parseCfg
fmap
的{{1}}返回值。
结果函数如下所示:
config
以下是您的程序,已修改为使用上述eitherDecode
运行。
parseCfg :: ByteString -> Either String Config
parseCfg json = config <$> eitherDecode json
这是经过修改的parseCfg
。原始文件包含两个{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TemplateHaskell #-}
import Data.ByteString.Lazy as B
import Data.Aeson
import Data.Aeson.TH
import GHC.Generics
import Control.Monad.IO.Class
data CfgProperty = CfgProperty {
env :: String,
host :: String,
port :: String,
directory :: String
} deriving (Show, Generic)
-- Instead of FromJSON, use deriveJSON for CfgProperty
-- which allows changing of field labels from lower
-- case to upper case.
$(deriveJSON
defaultOptions { fieldLabelModifier = let f "env" = "Env"
f "host" = "Host"
f "port" = "Port"
f "directory" = "Directory"
f other = other
in f
}
''CfgProperty
)
data Connections = Connections { cfgProperty :: CfgProperty
, connectionName :: String
} deriving (Show, Generic)
data Config = Config {connections :: [Connections]} deriving (Show, Generic)
data Cfg = Cfg { config :: Config } deriving (Show, Generic)
instance FromJSON Cfg
instance FromJSON Config
instance FromJSON Connections
jsonFile :: FilePath
jsonFile = "config/config.json"
getCfg :: IO ByteString
getCfg = B.readFile jsonFile
parseCfg :: ByteString -> Either String Config
parseCfg json = config <$> eitherDecode json
main :: IO()
main = do
json <- getCfg
case parseCfg json of
Left err -> Prelude.putStrLn err
Right cfg -> print cfg -- do whatever you want with cfg here.
config.json
条记录,它们之间没有任何内容,这些记录无效config
,与问题无关。
JSON