首先,您不能(至少以任何明显的方式)使用Language.Haskell.Interpreter
提示包来执行此操作。该模块中的函数用于读取和运行 Haskell 代码,而不是任意结构化数据。
要读取结构化数据,您将需要某种解析器。以下是您拥有的一些选项:
- 使用诸如Happy之类的解析器生成器。
- 使用解析器组合库,例如uu-parsinglib或parsec。
- 直接实现自己的解析器。
- 利用
Read
类的自动派生实例。
广告 1. 和 2。
如果您需要读取的数据格式非常重要,或者如果您需要有用的错误消息以防解析失败,我建议您选择 1. 或 2. 并查阅相应工具和库的文档。请注意,您将需要一些时间来习惯它们的主要概念和界面。
广告 3。
如果您的数据格式足够简单(如您的示例中所示),并且如果您的愿望清单中没有大量错误报告,您可以轻松推出自己的解析器。
在您的示例中,配置文件本质上是键和值的列表,由换行符分隔。在 Haskell 中,我们可以通过字符串对的列表来表示这样的列表:
type Config = [(String, String)]
“解析”配置然后简化为:(1)将输入字符串拆分为行,(2)将每一行拆分为单词,(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
该函数将条目的键作为其第一个参数,并将一个将原始值字符串转换为适当类型的函数作为其第二个参数。对于纯文本配置值,我们可以简单地将标识函数传递给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)