Suppose you have a data structure with several value constructors, for example, a LogMessage data LogMessage , for example:
data LogMessage = Unknown String | LogMessage MessageType TimeStamp String
If the message can be parsed correctly, it contains additional data, then String . If it cannot be parsed, then this is just a catch-all Unknown String .
Or suppose you are working with something like an Either String String , so you can deal with a Left String or a Right String .
Now let's say that you want to apply the same processing steps to the underlying data, regardless of which value constructor it is in.
For example, I could find a specific word in the LogMessage lines, so I could have a function like this:
detectWord :: String -> LogMessage -> Bool detectWord s (Unknown m) = isInfixOf s (map toLower m) detectWord s (LogMessage _ _ m) = isInfixOf s (map toLower m)
or just that easy to write to handle an Either String String as input instead of LogMessage .
In both cases, I have to repeat the same code (part of isInfixOf ... ), because I need to extract the basic data, which it will work differently due to the matching patterns for different value constructors.
It’s bad that you need to repeat / copy-paste the code for each constructor of different values.
How to write such Haskell functions without copy / paste code? How can I write basic logic only once, but then explain how it should be used in many different constructors of value constructors?
Just moving it to a helper helper function will reduce the number of characters, but will not really solve the problem. For example, the following idea does not make sense with respect to “do not repeat yourself” than in the first case:
helper :: String -> String -> Bool helper sm = isInfixOf s (map toLower m) detectWord :: String -> LogMessage -> Bool detectWord s (Unknown m) = helper sm detectWord s (LogMessage _ _ m) = helper sm
There again we must say the same for every other template.