
Hi AntC, On Fri, Dec 13, 2013 at 12:04 AM, Anthony Clayden < anthony_clayden@clear.net.nz> wrote:
Questions: * These pile-ups of types (M1 D ... (M1 C ... (...))) seem hairy. Is that the best way to control the depth of recursion?
I think I would define a generic function |typeOfRecord :: a -> TypeRep|, which expects a newtype |a| and returns the |TypeRep| of its argument. Then I'd use that function instead of your call to |from| expecting to match on |M1 (M1 (M1 (K1 x)))|. I'd define that function as a regular generic consumer (like generic show), and give runtime errors for unexpected values (such as sums, or products, as we don't expect those in newtypes). The advantage of the "hairy types" you have right now is that these would be (obscure) compile-time errors.
* The suggestion from John Lato (see gist from his message http://www.haskell.org/pipermail/haskell-cafe/2013-October/111139.html ) uses a different style for the class types, avoiding the mysterious unbound typevar
class GConName a where getConName :: a -> String -- cp: class ... f where ... :: f a -> String
Are there places where one or other is more suitable? (I did try John's style at first, but the constraints got uglier.)
Perhaps this is more or less what I suggest above?
* The explicit data constructors in the pattern matching are a bit temperamental w.r.t. undefined values. (Specifically, my instance for (:*:) was crashing.) Should I use dummy `_` patterns throughout? (Then the type annotations are monsters!)
I don't see why you need |undefined| at all. Unless you are calling |tupToAttribs| with |undefined|; is that the case? Else, your generic function can just pattern-match on |a :*: b| on the product case, for example. Cheers, Pedro
Thank you AntC
_______________________________________________ Generics mailing list Generics@haskell.org http://www.haskell.org/mailman/listinfo/generics