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