TL; DR: I need help in determining how to generate code that will return one of a small number of data types (possibly only Double and Bool) from different fields on disparate records.
Long form: Assuming the following data types
data Circle = Circle { radius :: Integer, origin :: Point } data Square = Square { side :: Integer }
and some boilerplate code
circle = Circle 3 (Point 0 0) square = Square 5
I am creating a small DSL and want the user to write something like the following
circle.origin square.side
and it will generate code similar to
origin . circle side . square
When analyzing this, for example, I would have the lines "circle" and "origin." Now I need to turn them into function calls. I could have something like this:
data Expr a = IntegerE (a -> Integer) | PointE (a -> Point) lookupF2I "side" = Just $ IntegerE side lookupF2I "radius" = Just $ IntegerE radius lookupF2I _ = Nothing lookupF2P "origin" = Just $ PointE origin lookupF2P _ = Nothing
and have one search function for the returned data type. Having one function for each data type is practical from the point of view of DSL, since it really will only deal with 2 or 3 data types. However, this hardly seems to be a particularly effective way of doing things. Is there a better way (of course) to do this? If not, is there a way that I can generate code for various search functions from various records that I want to be able to search for fields?
Secondly, there is still the question of parsing "circle" or "square" , which should call the corresponding function circle or square . If I implemented this using type classes, I could do something like:
instance Lookup Circle where lookupF2I "radius" = Just $ IntegerE radius lookupF2I _ = Nothing lookupF2P "origin" = Just $ PointE origin lookupF2P _ = Nothing
but then it leaves me the opportunity to figure out what type is forcibly applied to the search function, and the worse it is to be able to manually record instances for each (of many) records that I want to use.
Note. The fact that circle and square can be represented using a single ADT relates to my question in that this is a contrived example. The actual code will entail various very different entries, the only thing they have in common is fields of the same type.