
John Fouhy wrote:
[...] data Thing = Thing { field_one :: String, field_two :: String, field_three :: Integer }
type BooleanOp a = a -> a -> Bool type Field a = Thing -> a
data ThingCompare a = TC (BooleanOp a) (Field a) | And (ThingCompare a) (ThingCompare a) | Or (ThingCompare a) (ThingCompare a) [...] tcEqOne = TC (==) field_one tcEqTwo = TC (==) field_two tcGtThree = TC (>) field_three
I'm not quite sure what you want to do with explicitly represented comparisons. Maybe optimize them afterwards? Otherwise, BoolOp is likely to be your best comparison representation. You can separate the Field and the BoolOp parts with a small combinator by :: BoolOp a -> (b -> a) -> BoolOp b by f g x y = f (g x) (g y) Then, the three comparisons become tcEqOne = (==) `by` field_one tcEqTwo = (==) `by` field_two tcGtThree = (>) `by` field_three Appealing to the famous instance Monad ((->) a), you can also say and, or :: BoolOp a -> BoolOp a -> BoolOp a and = liftM2 $ liftM2 (&&) or = liftM2 $ liftM2 (||) Regards, apfelmus