3
votes

From the book Programming in Haskell (http://www.cs.nott.ac.uk/~gmh/book.html), a parser is defined as follows:

> type Parser a = String -> [(a,String)]

However, from the sample code (http://www.cs.nott.ac.uk/~gmh/Parsing.lhs), the definition is a little bit different.

> newtype Parser a              =  P (String -> [(a,String)])

I found the difference from this page:https://wiki.haskell.org/Type#Type_and_newtype as follows:

type introduces a synonym for a type and uses the same data constructors. newtype introduces a renaming of a type and requires you to provide new constructors.

Here are my questions:

  1. For new type why P(...) is used to enclose the content?
  2. It requires to provide new constructor with newtype, but I don't seem to find one from the example code. How to define constructor for newtype? Is it OK not to provide one?
1
P is the new constructor.Daniel Wagner

1 Answers

7
votes

For new type why P(...) is used to enclose the content?

Any newtype declared type must have a single constructor. In this case that constructor is named P and its type is

P :: (String -> [(a, String)]) -> Parser a

You can also use record syntax, so it would be equivalent to

newtype Parser a = P { runParser :: String -> [(a, String)] }

Or if you were to use a data type (in which case the wrapper does not get optimized away at runtime as easily), it would be very similar:

data Parser a = P { runParser :: String -> [(a, String)] }

It requires to provide new constructor with newtype, but I don't seem to find one from the example code. How to define constructor for newtype? Is it OK not to provide one?

As mentioned above, the constructor to the newtype Parser is named P, and there must be exactly one constructor for a newtype.

Some more clarification, the type keyword constructs a simple alias. For example, String is defined as

type String = [Char]

You can use String in any function that takes [Char], and you can use [Char] in any function that takes String. Since FilePath is defined as

type FilePath = String

Then you can use FilePath where ever you would use a String and thus anywhere you would use [Char], and vice versa. These are simply names for reducing more complicated types. I would say that in practice it's more common to use newtype rather than type except in very simple cases, simply because it allows the type system to enforce things more in your software. There are also disadvantages to types, since you need language extensions to use them in instance declarations, and they must always be fully applied in other expressions. The disadvantages of newtype is that you have to wrap/unwrap them a lot, but this can be more of a boon when working with truly complex programs.