I seem to have got myself stuck in an interesting edge-case of the language here. It's tricky to explain what I'm trying to do, so let me write it in code instead:
data Foobar x =
Foo1 {field1 :: x, field2 :: String} |
Foo2 {field1 :: x, field3 :: Int} |
Foo3 { field4 :: Bool} |
Foo4 { field2 :: String, field4 :: Bool}
As you can see, some constructors depend on x
, but others do not. I'm trying to write a function similar to fmap
:
transform :: (x -> y) -> Foobar x -> Foobar y
transform fn foobar =
case foobar of
Foo1 {} -> foobar {field1 = fn (field1 foobar)}
Foo2 {} -> foobar {field1 = fn (field1 foobar)}
_ -> foobar
As you can see, record syntax neatly lets me avoid having to rebuild the entire constructor, applying fn
only where it is needed. Unfortunately, this breaks when fn
is needed in zero places. In that case (i.e., the final alternative), the expression fails to type-check. It is quite clear to me why it fails - but I'm mystified as to how to fix this.
Obviously I could just write out the entire thing long-hand. That would work for this cut-down example, but the real application I'm trying to write is quite a lot larger. (About 25 constructors, some of them with upwards of 15 fields.)
Does anybody have any neat ideas on how I can fix this glitch?