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

时间:2018-07-17 07:31:03

标签: haskell

我有这样的类型:

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

type Code = Int

type Info = String

data Message = Message MessageType Code Info

和一个接受字符串并返回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**

我的意思是说值构造器不能部分地折叠使用。没有办法做到这一点吗?

1 个答案:

答案 0 :(得分:1)

如果我理解正确,那么您基本上想在构造函数中解析三个参数。这并不是foldrfoldl应该做的事情。 foldr基本上是列表上的同形性。将(:)替换为f,并将[]替换为初始累加器x0。但是由于列表中的元素数量在编译时未知,因此f的类型始终需要具有 same 类型:a -> b -> ba列表中元素的类型,以及b折叠输出的类型。

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

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

因此,我们将words的{​​{1}}拆包成linestsc,然后处理首先,将其余元素转换为sr的参数(通过Message函数将字符串转换为相应的mtype),它将第二个参数读取为MessageType ,最后将Int生成为rest。这些参数然后用于构造消息。