I have a type like this:
data MessageType = Debug | Error deriving (Show, Eq)
type Code = Int
type Info = String
data Message = Message MessageType Code Info
and a function that takes a string and returns a Message
:
parseMsg :: String -> Message
So far I've written a rough state machine:
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
But I'd rather do this in an actual foldl
or foldr
.
foldl (\msgVConstructor el -> msgVConstructor el) LogMessage (words line)
The idea is to fold a function (Message -> String -> Message)
so that the accumulator, Message
is partially applied across the words in the string. However, I get this error
Constructor ‘Message’ should have 3 arguments, but has been given none**strong text**
I'm taking this to mean that a value constructor can't be partially applied in a fold. Is there no way to do this?
Well if I understand it correctly, you basically want to parse three arguments in a constructor. This is not really what a foldr
or foldl
is supposed to do. foldr
basically is a catamorphism over a list. You replace the (:)
with f
, and the []
with the initial accumulator x0
. But since the number of elements in a list is not known at compile time, the type of f
always need to have the same type: a -> b -> b
with a
the type of elements in the list, and b
the type of the output of the fold.
If we however take a closer look to the code you provide, this does not look like a fold
at all. You basically have a constructor with three elements, and aim to convert these into a Message
. You can do so by interpreting the arguments separately:
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
We thus unpack the words
of the line
into st
, sc
, and sr
, and then process the first, second an remaining elements into parameters of the Message
(with mtype
a function that translates the string into the corresponding MessageType
), it reads the second parameter as an Int
, and finally generate the rest
as unwords sr
. These parameters are then used to construct a message.