Alistair Bayley wrote: > There's a small problem: how to write a factory function that returns values > of various subtypes. The makeSubType function below won't compile, obviously > because the returns types are different (they're not the same 'm').
Indeed, expressions in both branches of an `if' statement > if s == "SubBase1" > then SubBase1 3 > else SubBase2 (SubBase1 4) must be of the same type. If we had intersection types (I'm not complaining!), the compiler would have derived the intersection by itself. As things are now, we have to make the intersection manually: we have to abstract away irrelevant pieces. Expressions `SubBase1 3' and `SubBase2 (SubBase1 4)' have in common the fact that both have types that are instances of a Method class. So, we have to write that common piece of information explicitly. There are two ways of doing this, which can be called direct style and CPS style. In direct style, we do > data WM = forall m. Method m => WM m > makeSubType1 :: String -> WM > makeSubType1 s = > if s == "SubBase1" > then WM $ SubBase1 3 > else WM $ SubBase2 (SubBase1 4) > > test1 = let foo x = case x of WM y -> method2 y > in map (foo . makeSubType1) ["SubBase1", "SubBase2"] The CPS style is just the inverse: > -- Higher-ranked type: signature is required! > makeSubType2:: (forall m. Method m => m -> w) -> String -> w > makeSubType2 consumer s = > if s == "SubBase1" > then consumer $ SubBase1 3 > else consumer $ SubBase2 (SubBase1 4) > > test2 = let foo x = method2 x > in map (makeSubType2 foo) ["SubBase1", "SubBase2"] The CPS style involves less tagging (no need to add and remove the tag WM). Also, the CPS style is more general: > makeSubType1' s = makeSubType2 WM s > > test3 = let foo x = case x of WM y -> method2 y > in map (foo . makeSubType1') ["SubBase1", "SubBase2"] _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe