The real-world code my problem stems from is much more complicated than the following example (consisting of several mock functions). This example should illustrate the phenomenon my problem produces: (either) a huge table in a case/of statement (or a huge cascade of nested ifs). The case/of statement contains something similar to a truth table which decides how to parameterize the type of the result record (which is called ComposedRecord because it is a composition of three records of generic types). The mocked functions are already implemented, but I am not happy with the huge case/of block. Thus I am trying to find a more concise solution:
-- intermediate record type 1
data SimpleRecord = SimpleRecord {
_description :: String
}
-- intermediate record type 2
data DetailedRecord = DetailedRecord {
_title :: String,
_details :: String
}
-- intermediate record type 3
data RawRecord = RawRecord {
_x :: Int,
_y :: Int,
_z :: Int
}
class AnyRecord r where
instance AnyRecord SimpleRecord
instance AnyRecord DetailedRecord
instance AnyRecord RawRecord
-- to-be-serialized record type (composed of intermediate record types 1, 2 or 3)
data ComposedRecord a b c = ComposedRecord {
_a :: a,
_b :: b,
_c :: c
}
inputToSimpleRecord :: String -> SimpleRecord
inputToSimpleRecord input = SimpleRecord {
_description = "description derived from input"
}
inputToDetailedRecord :: String -> DetailedRecord
inputToDetailedRecord input = DetailedRecord {
_title = "title derived from input",
_details = "details derived from input"
}
inputToRawRecord :: String -> RawRecord
inputToRawRecord input = RawRecord {
_x = 1, -- number derived from input string
_y = 2, -- number derived from input string
_z = 3 -- number derived from input string
}
serializeToJsonString :: (AnyRecord a, AnyRecord b, AnyRecord c) => ComposedRecord a b c -> String
serializeToJsonString composedRecord = "{}"
-- this function will also contain some post processing of the records
-- thus the "AnyRecord" type constraint is needed
commandLineArguments = ["simple", "detailed", "raw"]
-- the value of commandLineArguments will be read from the command line
inputFromCommandLine = "1, 2, 3" -- some input
main = do
let result = case commandLineArguments of
["simple", "simple", "simple"] -> serializeToJsonString ComposedRecord {
_a = inputToSimpleRecord inputFromCommandLine,
_b = inputToSimpleRecord inputFromCommandLine,
_c = inputToSimpleRecord inputFromCommandLine
}
["simple", "simple", "detailed"] -> serializeToJsonString ComposedRecord {
_a = inputToSimpleRecord inputFromCommandLine,
_b = inputToSimpleRecord inputFromCommandLine,
_c = inputToDetailedRecord inputFromCommandLine
}
["simple", "simple", "raw"] -> serializeToJsonString ComposedRecord {
_a = inputToSimpleRecord inputFromCommandLine,
_b = inputToSimpleRecord inputFromCommandLine,
_c = inputToRawRecord inputFromCommandLine
}
["simple", "detailed", "simple"] -> serializeToJsonString ComposedRecord {
_a = inputToSimpleRecord inputFromCommandLine,
_b = inputToDetailedRecord inputFromCommandLine,
_c = inputToSimpleRecord inputFromCommandLine
}
["simple", "detailed", "detailed"] -> serializeToJsonString ComposedRecord {
_a = inputToSimpleRecord inputFromCommandLine,
_b = inputToDetailedRecord inputFromCommandLine,
_c = inputToDetailedRecord inputFromCommandLine
}
["simple", "detailed", "raw"] -> serializeToJsonString ComposedRecord {
_a = inputToSimpleRecord inputFromCommandLine,
_b = inputToDetailedRecord inputFromCommandLine,
_c = inputToRawRecord inputFromCommandLine
}
["simple", "raw", "raw"] -> serializeToJsonString ComposedRecord {
_a = inputToSimpleRecord inputFromCommandLine,
_b = inputToRawRecord inputFromCommandLine,
_c = inputToRawRecord inputFromCommandLine
}
["detailed", "simple", "simple"] -> serializeToJsonString ComposedRecord {
_a = inputToDetailedRecord inputFromCommandLine,
_b = inputToSimpleRecord inputFromCommandLine,
_c = inputToSimpleRecord inputFromCommandLine
}
-- and so on...
putStrLn result