Search code examples
haskellnewtype

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!


Solution

  • 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".