我有这样的类型:
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
但是我宁愿在实际的foldl
或foldr
中执行此操作。
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**
我的意思是说值构造器不能部分地折叠使用。没有办法做到这一点吗?
答案 0 :(得分:1)
如果我理解正确,那么您基本上想在构造函数中解析三个参数。这并不是foldr
或foldl
应该做的事情。 foldr
基本上是列表上的同形性。将(:)
替换为f
,并将[]
替换为初始累加器x0
。但是由于列表中的元素数量在编译时未知,因此f
的类型始终需要具有 same 类型:a -> b -> b
和a
列表中元素的类型,以及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}}拆包成line
,st
和sc
,然后处理首先,将其余元素转换为sr
的参数(通过Message
函数将字符串转换为相应的mtype
),它将第二个参数读取为MessageType
,最后将Int
生成为rest
。这些参数然后用于构造消息。