Ten Cache Misses

Crushing Haskell like a Tin Can

Record update for insufficiently polymorphic field

I often have the luxury of finding all sorts of underdocumented compile errors in GHC, and today was no exception. This wasn’t the first time I’ve hit this one in particular but it’s the first time I didn’t have a easy work around.

Let’s say you have a GADT and you’d like to update a field in said GADT

1
2
3
4
5
6
7
8
9
10
11
12
13
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE NamedFieldPuns #-}

class SomeClass a where
  someFunc :: a -> a

data SomeData = forall a . SomeClass a => SomeData
  { field1 :: Int
  , field2 :: a }

instance SomeClass SomeData where
  someFunc s@SomeData{field1, field2} = s{field1, field2 = someFunc field2}

You will instead be rewarded with this fine message:

PolyUpdate.hs:13:41:
    Record update for insufficiently polymorphic field: field2 :: a
    In the expression: s {field1, field2 = someFunc field2}
    In an equation for `someFunc':
        someFunc s@(SomeData {field1, field2})
          = s {field1, field2 = someFunc field2}
    In the instance declaration for `SomeClass SomeData'

There is some discussion on the GHC ticket #2595 regarding the improvements that led to this error, one can only imagine it was worse before. The verbage implies there is an easy fix (and there might be) to actually get the updates to work… by making the field more polymorphic? Either way, it seems easy enough to fix it by not doing an update and just copying all the fields… with or without wildcards:

1
2
3
4
{-# LANGUAGE NamedFieldPuns #-}

instance SomeClass SomeData where
  someFunc SomeData{field1, field2} = SomeData{field1, field2 = someFunc field2}
1
2
3
4
{-# LANGUAGE RecordWildCards #-}

instance SomeClass SomeData where
  someFunc SomeData{..} = SomeData{field2 = someFunc field2, ..}

Both compile to the same Core.

Comments