Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why haskell use a type of ReadS a to represent a function?

I am reading the source code of reads. reads is defined as reads :: Read a => ReadS a So it simply returns ReadS a while a has to be a instance of Read.

And ReadS a is defined as type ReadS a = String -> [(a, String)], so the thing returned from reads is only a function that take a string and return an array of tuple.

Then I wonder why just define reads without ReadS a. Just like reads :: Read a => (String -> [(a, String)])

like image 240
code4j Avatar asked Aug 11 '13 18:08

code4j


People also ask

What is type A in Haskell?

in https://www.haskell.org/tutorial/goodies.html type [a] is defined as followed: [a] is the family of types consisting of, for every type a, the type of lists of a. Lists of integers (e.g. [1,2,3]), lists of characters (['a','b','c']), even lists of lists of integers, etc., are all members of this family.

What does the read function do in Haskell?

In Haskell read function is used to deal with strings, if you want to parse any string to any particular type than we can use read function from the Haskell programming. In Haskell read function is the in built function, that means we do not require to include or install any dependency for it, we can use it directly.

What type is a function in Haskell?

Haskell has first-class functions : functions are values just like integers, lists, etc. They can be passed as arguments, assigned names, etc. … val is value of type Int , and half_of is a value of type Float -> Float .

How do you define a function in Haskell?

The most basic way of defining a function in Haskell is to ``declare'' what it does. For example, we can write: double :: Int -> Int double n = 2*n. Here, the first line specifies the type of the function and the second line tells us how the output of double depends on its input.


1 Answers

A parser for things
is a function from strings
to lists of pairs
of things and strings!

— Various sources

It aids in reasoning about programs to think about abstractions in terms of their intent, rather than their implementation. So yes, while type ReadS a = String -> [(a, String)], that’s secondary to the actual goal of parsing things, and of chaining ReadS parsers together. As Rhymoid points out:

composeReads :: ReadS a -> ReadS b -> ReadS (a,b)

Conveys the intent of parser composition, and as a happy side effect is much more succinct, than the inlined equivalent:

composeReads
  :: (String -> [(a, String)])
  -> (String -> [(b, String)])
  -> (String -> [((a, b), String)])

It’s a good and obvious thing to factor out this repetition, not least because it’s good to avoid repetition, but also to increase as much as possible the amount of useful semantic content per line. And if we want to change things about how these parsers are implemented, then encapsulating them behind this alias is a small step that may let us avoid massive changes to every single usage site.

You see this repeated in the various parser combinator libraries such as Parsec, Attoparsec, and uu-parsinglib. A Parser is a Parser is a Parser, and the more like a black box these things are, the easier it is to play with their usage and implementation—separately.

like image 92
Jon Purdy Avatar answered Nov 06 '22 16:11

Jon Purdy