我希望让我的Haskell程序从外部文件中读取设置,以避免重新编译以进行微小更改。熟悉YAML,我认为这是一个不错的选择。现在我必须把两件放在一起。到目前为止,Google一直没有太大的帮助。
非常感谢一个处理从文件中读取和解构YAML的示例代码。
答案 0 :(得分:25)
如果我对可用的软件包感兴趣,我会去hackage,查看完整的软件包列表,然后只搜索关键字。这样做会带来这些选择(以及其他一些不太引人注目的选择):
和HsSyck周围的包装器叫做yaml-light:http://hackage.haskell.org/package/yaml-light
yaml和HsSyck最近都看起来更新了,并且似乎被广泛使用的其他软件包使用。您可以通过查看反向代码来看到这一点:
在这两者中,yaml有更多的deps,但这是因为它是yesod生态系统的一部分。一个依赖于HsSyck的库是yst,我碰巧知道它是积极维护的,所以这向我表明HsSyck也很好。
我做出选择的下一步是浏览两个库的文档,看看哪个库更适合我的目的。
在这两者中,看起来HsSyck暴露了更多的结构,但没有多少其他,而yaml通过aeson提供的json编码。这向我表明,前者可能更强大,而后者更方便。
答案 1 :(得分:10)
一个简单的例子:
首先,您需要一个test.yml
文件:
db: /db.sql
limit: 100
在Haskell中阅读YAML
{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics
import Data.Yaml
data Config = Config { db :: String
, limit :: Int
} deriving (Show, Generic)
instance FromJSON Config
main :: IO ()
main = do
file <- decodeFile "test.yml" :: IO (Maybe Config)
putStrLn (maybe "Error" show file)
答案 2 :(得分:1)
使用yamlparse-applicative
,您可以在static analysis-friendly way中描述YAML解析器,因此可以从解析器中免费获取YAML格式的描述。我将为此使用Matthias Braun's example format:
Name:
ABCTEST
请注意,{-# LANGUAGE ApplicativeDo, RecordWildCards, OverloadedStrings #-}
import Data.Yaml
import Data.Aeson.Types (parse)
import YamlParse.Applicative
import Data.Map (Map)
import qualified Data.Text.IO as T
data MyType = MyType
{ stringsToStrings :: Map String String
, mapOfLists :: Map String [String]
} deriving Show
parseMyType :: YamlParser MyType
parseMyType = unnamedObjectParser $ do
stringsToStrings <- requiredField' "strings_to_strings"
mapOfLists <- requiredField' "map_of_lists"
pure MyType{..}
main :: IO ()
main = do
T.putStrLn $ prettyParserDoc parseMyType
yaml <- decodeFileThrow "config/example.yaml"
print $ parse (implementParser parseMyType) yaml
甚至可以在看到实例之前打印出架构:
main
答案 3 :(得分:0)
以下是使用yaml
库从YAML文件中解析特定对象的方法。
让我们解析该文件的一部分,config/example.yaml
:
# A map from strings to strings
strings_to_strings:
key_one: val_one
key_two: val_two
# A map from strings to list of strings
map_of_lists:
key_one:
- val_one
- val_two
- val_three
key_two:
- val_four
- val_five
# We won't parse this
not_for: us
此模块分别解析strings_to_strings
和map_of_lists
并将它们放入自定义记录MyType
:
{-# Language OverloadedStrings, LambdaCase #-}
module YamlTests where
import Data.Yaml ( decodeFileEither
, (.:)
, parseEither
, prettyPrintParseException
)
import Data.Map ( Map )
import Control.Applicative ( (<$>) )
import System.FilePath ( FilePath
, (</>)
)
data MyType = MyType {stringsToStrings :: Map String String,
mapOfLists :: Map String [String]} deriving Show
type ErrorMsg = String
readMyType :: FilePath -> IO (Either ErrorMsg MyType)
readMyType file =
(\case
(Right yamlObj) -> do
stringsToStrings <- parseEither (.: "strings_to_strings") yamlObj
mapOfLists <- parseEither (.: "map_of_lists") yamlObj
return $ MyType stringsToStrings mapOfLists
(Left exception) -> Left $ prettyPrintParseException exception
)
<$> decodeFileEither file
yamlTest = do
parsedValue <- readMyType $ "config" </> "example.yaml"
print parsedValue
运行yamlTest
以查看解析结果。