在列表上折叠部分应用的值构造函数?

Fold a partially applied value constructor over a list?

我有这样的类型:

data MessageType = Debug | Error deriving (Show, Eq)

type Code = Int

type Info = String

data Message = Message MessageType Code Info

和一个接受字符串和 returns 一个 Message:

的函数
parseMsg :: String -> Message

到目前为止我已经写了一个粗略的状态机:

parseMsg line = fold (words line) Message
  where fold ("D":xs) msgCtr = fold' xs (msgCtr Debug)
        fold ("E":xs) msgCtr = fold' xs (msgCtr Error)
        fold' (code:xs) msgCtr = fold'' xs (msgCtr (readCode code))
        fold'' rest msgCtr = msgCtr (unwords rest)
        readCode code = read code::Int

但我更愿意在实际的 foldlfoldr 中执行此操作。

foldl (\msgVConstructor el -> msgVConstructor el) LogMessage (words line)

这个想法是折叠函数 (Message -> String -> Message) 以便累加器 Message 部分应用于字符串中的单词。但是,我得到这个错误

Constructor ‘Message’ should have 3 arguments, but has been given none**strong text**

我的意思是值构造函数不能在折叠中部分应用。有没有办法做到这一点?

嗯,如果我没理解错的话,你基本上想在构造函数中解析三个参数。这实际上不是 foldrfoldl 应该做的。 foldr 基本上是对列表的 变形 。您将 (:) 替换为 f,并将 [] 替换为初始累加器 x0。但是由于在编译时不知道列表中的元素数量,因此 f 的类型总是需要具有 相同的 类型: a -> b -> ba 列表中元素的类型,b 折叠输出的类型。

但是,如果我们仔细查看您提供的代码,就会发现这 根本不像 fold。您基本上有一个包含三个元素的构造函数,目标是将它们转换为 Message。您可以通过分别解释参数来做到这一点:

parseMsg line = Message (<b>mtype</b> st) <b>code</b> <b>rest</b>
    where (st : sc : sr) = words line
          <b>mtype</b> "D" = Debug
          <b>mtype</b> "E" = Error
          <b>code</b> = read sc :: Int
          <b>rest</b> = unwords sr

我们因此linewords解包stscsr ,然后将第一个,第二个和剩余的元素处理成Message的参数(用mtype一个函数将字符串翻译成对应的MessageType),它读取第二个参数作为一个Int,最后将rest生成为unwords sr。然后使用这些参数来构建消息。