A little test:
newtype (FComp g f) x = FComp { unCompose :: g (f x) }
newtype FComp2 g f x = FComp2 { unCompose2 :: g (f x) }
*Main> :i FComp
newtype FComp g f x = FComp {unCompose :: g (f x)}
-- Defined at Test.hs:34:10
*Main> :i FComp2
newtype FComp2 g f x = FComp2 {unCompose2 :: g (f x)}
-- Defined at Test.hs:35:9
So the parentheses really don't change anything. It's just the same as without them.
As for the uncompose
, it's just a name to unwrap the newtype
without making the data constructor explicit. In the snippet you posted they use pattern matching, but one wouldn't want to export the implementation details, so unCompose
is provided to use the contents of FComp
. This is just the same as in data
definitions, only that newtype
wants exactly one field instead of 0..n.