
#13465: Foldable deriving treatment of tuples is too surprising -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.4.1 Component: Compiler | Version: 8.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: Other | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by RyanGlScott): * cc: twanvl (added) Comment: Ick. This is an eccentricity of `DeriveFunctor`/`DeriveFoldable`/`DeriveTraversable` that I've never been keen on fixing, but since folks are complaining about it, I suppose it should at least be addressed. It's a somewhat obscure piece of GHC trivia that `DeriveFunctor` //et al.// special-cases two type constructors: 1. `(->)` 2. Tuples The `(->)` special case is somewhat justifiable, as it's quite common to define `Functor` instances where the type parameter occurs to the left of an arrow. The tuples special-casing is more confusing to me, as I'm not sure what practical purpose it serves. I've cc'd twanvl, the original author of these `deriving` extensions, in case he can share some insight on why he chose to implement it that way. I too think the Right Thing™ to do here is to change the behavior so that we just call `fmap`/`foldMap`/`traverse` on occurrences of tuple types, and reject things like `data Foo a = Foo (a, a) deriving (Functor, Foldable, Traversable)`. But there's one thorny corner case to watch out for: unboxed tuples. An even more obscure piece of GHC trivia is that you can do this: {{{#!hs data Foo a = Foo (# a, a #) deriving (Functor, Foldable) }}} This is only possible because of special-casing, as calling `fmap`/`foldMap` on an entire unboxed tuple is ill-kinded (unless we were to adopt [https://ghc.haskell.org/trac/ghc/ticket/12708 levity-polymorphic versions] of `Functor` and `Foldable`, I suppose). Moreover, it would feel weird to allow `data Foo a = Foo (# a, a #)` but not `data Foo a = Foo (a, a)`. I suppose we could tweak the special-casing so that we reject unboxed tuples where the type parameter occurs somewhere other than the last field, which would at least make its behavior consistent with that of boxed tuples. But the biggest roadblock by far is that this would (1) make fewer programs compile than before, and (2) change the behavior of existing programs. I think we should definitely get some kind of community consensus (i.e., a GHC proposal) before marching forth with this, although I have a funny feeling that discussing the behavior of `deriving Foldable` on tuple types is not going to go well... -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13465#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler