4

Language.Haskell.Interpreter を使用して、指定された構成ファイルを読み取り、その中で指定された値を割り当てて、プログラム内の変数を初期化するにはどうすればよいですか?

私の設定ファイルは次のようなものです:

numRecords = 10
numFields = 3
inputFile = /home/user1/project/indata.file
outputFile = /home/user1/project/outdata.file
datefmt = ddmmyyyy

構成ファイルで指定された値を使用して、構成ファイルで指定された識別子に対応する変数を初期化したいと考えています。

Language.Haskell.Interpreter を使用してこのことを達成するにはどうすればよいですか? IO モナドとインタープリター モナドのせいで混乱しています。この種の小さな例も役に立ちます。

4

2 に答える 2

4

Language.Haskell.Interpreterまず第一に、これを行うためにヒントパッケージを使用することは (少なくとも明白な方法では) できません。そのモジュールのその関数は、任意の構造化データではなく、Haskell コードを読み込んで実行するために使用されます。

構造化データを読み取るには、何らかのパーサーが必要です。以下にいくつかのオプションを示します。

  1. Happyなどのパーサー ジェネレーターを使用します。
  2. uu-parsinglibparsecなどのパーサー コンビネーター ライブラリを使用します。
  3. 独自のパーサーを直接実装します。
  4. クラスの自動派生インスタンスを利用しますRead

広告 1. と 2.

読み込む必要があるデータの形式が重要である場合、または解析が失敗した場合に役立つエラー メッセージが必要な場合は、1. または 2. を選択し、それぞれのツールとライブラリのドキュメントを参照することをお勧めします。それらの主な概念とインターフェイスに慣れるには、ある程度の時間がかかることに注意してください。

広告 3.

データの形式が十分に単純で (例のように)、広範なエラー レポートが希望リストの上位にない場合は、独自のパーサーを簡単に作成できます。

あなたの例では、構成ファイルは基本的に改行で区切られたキーと値のリストです。Haskell では、このようなリストを文字列のペアのリストで表すことができます。

type Config = [(String, String)]

構成を「解析」すると、次のようになります。(1) 入力文字列を行に分割する、(2) 各行を単語に分割する、(3) 各行から最初と 3 番目の単語を選択する:

readConfig :: String -> Config
readConfig s =
  [(key, val) | line <- lines s, let (key : _ : val : _) = words line]

解析された構成ファイルからエントリを取得するには、関数を使用できますget

get :: String -> (String -> a) -> Config -> a
get key f config = case lookup key config of
  Nothing -> error ("get: not found: " ++ key)
  Just x  -> f x

この関数は、最初の引数としてエントリのキーを受け取り、2 番目の引数として生の値の文字列を適切な型に変換する関数を受け取ります。純粋にテキストの構成値の場合、アイデンティティ関数を に渡すだけですget

inputFile, outputFile, datefmt :: Config -> String
inputFile  = get "inputFile" id
outputFile = get "outputFile" id
datefmt    = get "datefmt" id

整数エントリの場合、次を使用できますread

numRecords, numFields :: Config -> Int
numRecords = get "numRecords" read
numFields  = get "numFields" read

おそらく、これらのパターンは、 の独自の専用バージョンに分解するのに十分一般的ですget

getS :: String -> Config -> String
getS key = get key id

getR :: Read a => String -> Config -> a
getR key = get key read

inputFile', outputFile', datefmt' :: Config -> String
inputFile'  = getS "inputFile"
outputFile' = getS "outputFile"
datefmt'    = getS "datefmt"

numRecords', numFields' :: Config -> Int
numRecords' = getR "numRecords"
numFields'  = getR "numFields"

例として、構成ファイルを読み取り、「outputFile」の値を出力するプログラムを次に示します。

main :: IO ()
main = do
  s <- readFile "config.txt"
  let config = readConfig s
  putStrLn (outputFile config)

広告 4。

構成ファイルの形式を制御できる場合は、構成データを保持するための新しいデータ型を導入し、Haskell にそのクラスのインスタンスを自動的に派生させることができますRead。例えば:

data Config = Config
  { numRecords :: Int
  , numFields  :: Int
  , inputFile  :: String
  , outputFile :: String
  , datefmt    :: String
  } deriving Read

ここで、構成ファイルが予想される形式と一致していることを確認する必要があります。例えば:

Config
  { numRecords = 10
  , numFields  = 3
  , inputFile  = "/home/user1/project/indata.file"
  , outputFile = "/home/user1/project/outdata.file"
  , datefmt    = "ddmmyyyy"
  }

例として、「outputFile」の値を出力するプログラムを次に示します。

main :: IO ()
main = do
  s <- readFile "config.txt"
  let config = read s
  putStrLn (outputFile config)
于 2013-05-24T07:06:33.663 に答える