Felix Benner
Felix Benner

Reputation: 268

Haskell newtype with parentheses

I'm trying to understand the explaination in Monads made difficult and I have a hard time figuring out the following newtype definition:

newtype (FComp g f) x = FComp { unCompose :: g (f x) }

instance (Functor b c f, Functor a b g) => Functor a c (FComp g f) where
  fmap f (FComp xs) = FComp $ fmap (fmap f) xs

I have nowhere seen an explaination of what newtype means with an expression in parentheses in place of the type declaration. I therefore cannot figure out what the definition of the fmap function means. I also don't understand why the unCompose field accessor is defined but never used. I feel like I am missing some basic semantics of newtype.

Upvotes: 15

Views: 864

Answers (2)

Ingo
Ingo

Reputation: 36339

You could write this:

newtype (FComp g f) x = FComp { unCompose :: g (f x) }

like so:

newtype FComp g f x = FComp (g (f x))
unCompose (FComp it) = it

This is so because type application has the same syntactic properties as ordinary applications, i.e.:

a b c  = (a b) c

holds for values a,b,c and for types a,b,c.

Upvotes: 11

firefrorefiddle
firefrorefiddle

Reputation: 3805

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.

Upvotes: 16

Related Questions