Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Data declaration with no data constructor. Can it be instantiated? Why does it compile?

Tags:

types

haskell

Reading one of my Haskell books, I came across the sentence:

Data declarations always create a new type constructor, but may or may not create new data constructors.

It sounded strange that one should be able to declare a data type with no data constructor, because it seems that then one could never instantiate the type. So I tried it out. The following data declaration compiles without error.

data B = String

How would one create an instance of this type? Is it possible? I cannot seem to find a way.

I thought maybe a data constructor with name matching the type constructor would be created automatically, but that does not appear to be the case, as shown by the error resulting from attempting to use B as a data constructor with the declaration in scope.

Prelude> data B = String deriving Show
Prelude> B

<interactive>:129:1: error: Data constructor not in scope: B

Why is this data declaration permitted to compile if the type can never be instantiated? Is it permitted solely for some formal reason despite not having a known practical application?


I also wonder whether my book's statement about data types with no constructor might be referring to types declared via the type or newtype keywords instead of by data.

  • In the type case, type synonyms clearly do not use data constructors, as illustrated by the following.

    Prelude> type B = String
    Prelude>
    

    Type synonyms such as this can be instantiated by the constructors of the type they are set to. But I am not convinced that this is what my book is referring to as type synonyms do not seem to be declaring a new data type as much as simply defining an new alias for an existing type.

  • In the newtype case, it appears that types without data constructors cannot be created, as shown by the following error.

    Prelude> newtype B = String
    
    <interactive>:132:13: error:
        • The constructor of a newtype must have exactly one field
            but ‘String’ has none
        • In the definition of data constructor ‘String’
          In the newtype declaration for ‘B’
    

type and newtype do not appear to be what the book is referring to, which brings me back to my original question: why it is possible to declare a type using data with no data constructor?

like image 444
mherzl Avatar asked Jul 29 '17 05:07

mherzl


1 Answers

How would one create an instance of this type?

The statement from your book is correct, but your example is not. data B = String defines a type constructor B and a data constructor String, both taking no arguments. Note that the String you define is in the value namespace, so is different from the usual String type constructor.

ghci> data B = String
ghci> x = String
ghci> :t x
x :: B

However, here is an example of a data definition without data constructors (so it cannot be instantiated).

ghci> data B

Now, I have a new type constructor B, but no data constructors to produce values of type B. In fact, such a data type is declared in the Haskell base: it is called Void:

ghci> import Data.Void
ghci> :i Void
data Void   -- Defined in ‘Data.Void’

Why is this data declaration permitted to compile if the type can never be instantiated?

Being able to have uninhabited types turns out to be useful in a handful of places. The examples that I can think of right now are mostly passing in such a type as a type parameter to another type constructor. One more practical use case is in streaming libraries like conduit.

There is a ConduitM i o m r type constructor where: i is the type of the input stream elements, o the type of the output stream elements, m the monad in which actions are performed, r is the final result produced at the end.

Then, it defines a Sink as

type Sink i m r = ConduitM i Void m r

since a Sink should never output any values. Void is a compile time guarantee that Sink cannot output any (non-bottom) values.

Much like Identity, Void is mostly useful in conjunction with other abstractions.

... type synonyms clearly do not use data constructors

Yes, but they are not defining type constructors either. Synonyms are just some surface-level convenience renaming. Under the hood, nothing new is defined.

In the newtype case, it appears that types without data constructors cannot be created, as shown by the following error.

I suggest you look up what newtype is for. The whole point of newtype is to provide a zero-cost wrapper around an existing type. That means you have one and exactly one constructor taking one and exactly one argument (the wrapped value). At compile time, the wrapping and unwrapping operations become NOPs.

like image 200
Alec Avatar answered Nov 19 '22 02:11

Alec