Home > Back-end >  Understanding 'newtype' keyword
Understanding 'newtype' keyword

Time:11-17

For a uni assignment, we have been given a line of Haskell code which shows:

newtype TC a = TC ([Id] -> Either TypeError ([Id], a))

Firstly, TypeError is something which needs to be implemented by us for the assignment so I can't post the data declaration here, but my question is this. How do I read the code above? What is the a right after the newtype TC? I also don't understand how TC is being reused to the right of the equals sign.

I think a here is a type variable since newtype works similarly to data. I don't know how knowing this will help my understanding.

CodePudding user response:

What is the a right after the newtype TC?

The a in the newtype declaration

newtype TC a = ...

expresses much the same as the x in a function declaration

f x = ...

a is a type parameter. So you'll be able to use TC as, for example, TC Int or TC Bool, similar to how you're able to use f like f 1 or f "bla bla" (depending on its type).

The case TC Int is equivalent to the following alternative:

newtype TCInt = TCInt ([Id] -> Either TypeError ([Id], Int))

I also don't understand how TC is being reused to the right of the equals sign.

That is a bit of a confusing quirk in Haskell. Actually TC is not reused, rather you're declaring two separate entities which are both called TC. You could also call them differently:

newtype TC_T a = TC_V ([Id] -> Either TypeError ([Id], a))
  • TC_T is a type constructor. This is the thing that will appear in type signatures, i.e. TC_T Int or TC_T Bool.
  • TC_V is a value constructor. You use this when, well, generating values of type TC_T Int or TC_T Bool.

So for example, you might write these:

tci :: TC_T Int
tci = TC_V (\ids -> Right (ids, 37))

tcb :: TC_T Bool
tcb = TC_V (\ids -> Right (reverse ids, False))

With your original version it looks like this:

tci :: TC Int
tci = TC (\ids -> Right (ids, 37))

tcb :: TC Bool
tcb = TC (\ids -> Right (reverse ids, False))

...but it's still two separate things both called TV here. Most newtypes in Haskell call the type- and value constructors the same, but often only the type constructor is exported from a module and the value constructor left as an implementation detail.

Most of this is the same for data as for newtype. You could as well have

data TC a = TC ([Id] -> Either TypeError ([Id], a))

... the only difference to the newtype version is a subtle indirection: if it's data, then the compiler inserts an indirection which allows a bit more lazyness, but in this case there's hardly a point to doing that.

In practice, you generally use data only when you need multiple constructors and/or a constructor with multiple fields, which newtype does not support.

  • Related