Tshimanga
Tshimanga

Reputation: 885

"For all" statements in Haskell

I'm building comfort going through some Haskell toy problems and I've written the following speck of code

multipOf :: [a] -> (Int, a)
multipOf x = (length x, head x)
gmcompress x = (map multipOf).group $ x

which successfully preforms the following operation

gmcompress [1,1,1,1,2,2,2,3] = [(4,1),(3,2),(1,3)]

Now I want this function to instead of telling me that an element of the set had multiplicity 1, to just leave it alone. So to give the result [(4,1),(3,2),3] instead. It be great if there were a way to say (either during or after turning the list into one of pairs) for all elements of multiplicity 1, leave as just an element; else, pair. My initial, naive, thought was to do the following.

multipOf :: [a] -> (Int, a)
multipOf x = if length x = 1 then head x else (length x, head x)
gmcompress x = (map multipOf).group $ x

BUT this doesn't work. I think because the then and else clauses have different types, and unfortunately you can't piece-wise define the (co)domain of your functions. How might I go about getting past this issue?

Upvotes: 0

Views: 142

Answers (1)

Luis Casillas
Luis Casillas

Reputation: 30237

BUT this doesn't work. I think because the then and else clauses have different types, and unfortunately you can't piece-wise define the (co)domain of your functions. How might I go about getting past this issue?

Your diagnosis is right; the then and else must have the same type. There's no "getting past this issue," strictly speaking. Whatever solution you adopt has to use same type in both branches of the conditional. One way would be to design a custom data type that encodes the possibilities that you want, and use that instead. Something like this would work:

-- | A 'Run' of @a@ is either 'One' @a@ or 'Many' of them (with the number
-- as an argument to the 'Many' constructor).
data Run a = One a | Many Int a

But to tell you the truth, I don't think this would really gain you anything. I'd stick to the (Int, a) encoding rather than going to this Run type.

Upvotes: 3

Related Questions