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 }
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