マイナーな変更のための再コンパイルを避けるために、Haskell プログラムに外部ファイルから設定を読み取らせたいと考えています。YAML に精通していたので、これは良い選択だと思いました。今、私は2つの部分を一緒にする必要があります. Google はこれまであまり役に立ちませんでした。
ファイルからの YAML の読み取りと分解を扱う小さなサンプル コードは、非常に高く評価されます。
利用可能なパッケージに興味がある場合は、hackage にアクセスして完全なパッケージ リストを確認し、ページ内でキーワードを検索します。それを行うと、次の選択肢が表示されます (他のいくつかのあまり説得力のないものと一緒に):
yaml-light と呼ばれる HsSyck のラッパー: http://hackage.haskell.org/package/yaml-light
yaml と HsSyck はどちらも比較的最近更新されたようで、広く使用されている他のパッケージで使用されているようです。これは、リバース deps を確認することで確認できます。
2 つのうち、yaml にはより多くの dep がありますが、それは yesod エコシステムの一部であるためです。HsSyck に依存するライブラリの 1 つに yst があります。たまたま積極的にメンテナンスされていることを知っているので、HsSyck も問題ないことがわかります。
選択を行うための次のステップは、両方のライブラリのドキュメントを参照し、どちらが私の目的により魅力的な API を持っているかを確認することです。
2つのうち、HsSyckはより多くの構造を公開しているように見えますが、それ以外はあまり公開していません.yamlはaesonによって提供されたjsonエンコーディングを経由しています. これは、前者がおそらくより強力であり、後者がより便利であることを示しています。
簡単な例:
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)
yamlparse-applicative
YAML パーサーを静的分析に適した方法で記述できるため、パーサーから無料で YAML 形式の記述を取得できます。これにはMatthias Braun のサンプル形式を使用します 。
{-# 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
インスタンスを見る前にスキーマを出力できることに注意してください。
strings_to_strings: # required
<key>: <string>
map_of_lists: # required
<key>: - <string>
Success
(MyType
{ stringsToStrings = fromList
[ ("key_one","val_one")
, ("key_two","val_two")
]
, mapOfLists = fromList
[ ("key_one",["val_one","val_two","val_three"])
, ("key_two",["val_four","val_five"])
]
})