0

Currently I have faced the following code that I have no idea on how this data constructor works. The code snippet is as follow:

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

I understand that Haskell can have something called recorded syntax, but for this one, that is a bit blow my mind up.

Thanks for the help.

chungonion
  • 125
  • 3
  • 8
  • 1
    What part specifically are you having problems understanding? There's a lot going on here, and an overview of it all would be too broad. Have you looked how records work? – Carcigenicate Jun 04 '18 at 15:52
  • @Carcigenicate Stream a -> [(b, Stream a)] is this means if I type `:t runParser` in ghci, I will got `Parser a b -> Stream a -> [(b,Stream a)]` ??? – chungonion Jun 04 '18 at 15:55
  • Did you try that to see? And `Stream a -> [(b, Stream a)]` is a function that takes a Stream, and returns a list of tuples where the first element is of type b, and the second is a Stream of a's. – Carcigenicate Jun 04 '18 at 15:57
  • The record syntax does not change anything. In functional programming: functions are "*first class citizens*". You can pass them as arguments, return them as a result, and store them in a constructor. – Willem Van Onsem Jun 04 '18 at 16:11

1 Answers1

4

Well basically this is just regular record synax:

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

It means that the Parser a b data type has one data constructor. A data constructor named P, and that constructor has one argument: a "field" called runParser, and that field has type Stream a -> [(b, Stream a)].

This pattern is quite common in Haskell and in functional programming in general. Functions are "first class citizens". It means that functions can be passed as arguments, a function can return another function (in fact due to currying this happens very often in Haskell), and we can store (references to) function in a data constructor.

We can for example create a Parser Int Char type with:

P (\_ -> []) :: Parser Int Char

So here we constructed a Parser Int Char and the argument, a single function, maps any value to an empty list.

Or another example:

P (\x -> [('a', x), ('b', x)]) :: Parser Int Char

Here we thus map our Stream a object x, to a list of 2-tuples, one with 'a' as first element, and one with 'b' as first element. Each time we pick x as second element.

Or we can define a function, and pass a reference to that function:

f :: Stream Int -> [(Char, Stream Int)]
f x = [('a', x)]

P f :: Parser Int Char
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555