Tomer
Tomer

Reputation: 1229

Why the newtype syntax creates a function

I look at this declaration:

newtype Parser a = Parser { parse :: String -> Maybe (a,String) }

Here is what I understand:

1) Parser is declared as a type with a type parameter a

2) You can instantiate Parser by providing a parser function for example p = Parser (\s -> Nothing)

What I observed is that suddenly I have a function name parse defined and it is capable of running Parsers.

For example, I can run:

parse (Parser  (\s -> Nothing)) "my input" 

and get Nothing as output.

How was this parse function got defined with this specific signature? How does this function "know" to execute the Parser given to it? Hope that someone can clear my confusion.

Thanks!

Upvotes: 4

Views: 1006

Answers (2)

bradrn
bradrn

Reputation: 8467

First, let’s have a look at a parser newtype without record syntax:

newtype Parser' a = Parser' (String -> Maybe (a,String))

It should be obvious what this type does: it stores a function String -> Maybe (a,String). To run this parser, we will need to make a new function:

runParser' :: Parser' a -> String -> Maybe (a,String)
runParser' (Parser' p) i = p i

And now we can run parsers like runParser' (Parser' $ \s -> Nothing) "my input".

But now note that, since Haskell functions are curried, we can simply remove the reference to the input i to get:

runParser'' :: Parser' a -> (String -> Maybe (a,String))
runParser'' (Parser' p) = p

This function is exactly equivalent to runParser', but you could think about it differently: instead of applying the parser function to the value explicitly, it simply takes a parser and fetches the parser function from it; however, thanks to currying, runParser'' can still be used with two arguments.

Now, let’s go back to back to your original type:

newtype Parser a = Parser { parse :: String -> Maybe (a,String) }

The only difference between your type and mine is that your type uses record syntax, although it may be a bit hard to recognise since a newtype can only have one field; this record syntax automatically defines a function parse :: Parser a -> (String -> Maybe (a,String)), which extracts the String -> Maybe (a,String) function from the Parser a. Hopefully the rest should be obvious: thanks to currying, parse can be used with two arguments rather than one, and this simply has the effect of running the function stored within the Parser a. In other words, your definition is exactly equivalent to the following code:

newtype Parser a = Parser (String -> Maybe (a,String))

parse :: Parser a -> (String -> Maybe (a,String))
parse (Parser p) = p

Upvotes: 7

Juan Pablo Santos
Juan Pablo Santos

Reputation: 1220

When you write newtype Parser a = Parser { parse :: String -> Maybe (a,String) } you introduce three things:

  1. A type named Parser.

  2. A term level constructor of Parsers named Parser. The type of this function is

Parser :: (String -> Maybe (a, String)) -> Parser a

You give it a function and it wraps it inside a Parser

  1. A function named parse to remove the Parser wrapper and get your function back. The type of this function is:
parse :: Parser a -> String -> Maybe (a, String)

Check yourself in ghci:

Prelude> newtype Parser a = Parser { parse :: String -> Maybe (a,String) }
Prelude> :t Parser
Parser :: (String -> Maybe (a, String)) -> Parser a
Prelude> :t parse
parse :: Parser a -> String -> Maybe (a, String)
Prelude>

It's worth nothing that the term level constructor (Parser) and the function to remove the wrapper (parse) are both arbitrary names and don't need to match the type name. It's common for instance to write:

newtype Parser a = Parser { unParser :: String -> Maybe (a,String) }

this makes it clear unParse removes the wrapper around the parsing function. However, I recommend your type and constructor have the same name when using newtypes.

How does this function "know" to execute the Parser given to it

You are unwrapping the function using parse and then calling the unwrapped function with "myInput".

Upvotes: 8

Related Questions