Create record with all fields undefined, without triggering warning

Viewed 102

I'd like to create a value of a record type that can be pattern-matched, without filling any fields.

data Foo = MkFoo
    { field1 :: Int
    , field2 :: Bool
    }

fun :: Foo -> Bool
fun MkFoo{..} = True

bar :: Bool
bar = fun MkFoo{}

This works because all fields of the Foo passed to fun are undefined, and fun is lazy in them. Of course, fun undefined would fail, because fun pattern-matches on the record constructor MkFoo.

However, this causes a compiler warning:

• Fields of MkFoo not initialised: field1, field2

I would like to get rid of this warning for this specific instance. So I am not looking to turn off the warning in general (with -Wno-missing-fields). I am also not looking to change fun (I could just make the pattern matching on MkFoo irrefutable). I would also like to avoid having to write out all fields of MkFoo, as in

bar = fun MkFoo{ field1 = undefined, field2 = undefined }
1 Answers

As mentioned in the comments, one option is to use generics, either the vanilla version or a helper package like generics-sop:

{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-} -- derive stock, anyclass stuff
{-# LANGUAGE ImportQualifiedPost #-} -- GHC >= 8.10
import GHC.Generics
import Generics.SOP qualified as SOP
import Generics.SOP.NP (pure_NP)

data Foo
  = MkFoo
      { field1 :: Int,
        field2 :: Bool
      }
  deriving stock (Generic)
  deriving anyclass (SOP.Generic)

allundef :: Foo
allundef = SOP.productTypeTo $ pure_NP undefined
Related