Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell tuple constructor (GHC) and the separation between a language and its implementation

Haskell blew my mind yet again when I realised that

(x,y)

Is just syntactic sugar for

(,) x y

Naturally I wanted to extend this to larger tuples. But

(,) x ((,) y z)

Gave me

(x,(y,z))

Which was not what I was looking for. On a whim, I tried

(,,) x y z

And it worked, giving exactly what I wanted:

(x,y,z)

This raised the question: How far can you take it? Much to my astonishment, there seemed to be no limit. All of the below are valid operators:

(,)
(,,)
(,,,)
(,,,,)
--etc
(,,,,,,,,,,,,,,)
(,,,,,,,,,,,,,,,)
--etc
(,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,)
--etc

This behaviour is amazing and leads to my actual question: Is it something which can be emulated in my own functions? Or is it just a GHC-specific feature of the tuple operator? I'm thinking it's the latter as I've read the haskell98 specification and iirc it says that implementations only have to define the tuple operator for up to 15 items. Whereas GHC has gone the whole hog and let you do it up to arbitrary limits.

So, would it be possible to define this family of operators/functions from within the haskell implementation itself, using nothing but the type system and existing language features (declarations, type signatures, function definitions etc.)? And if so, how? Or is it impossible and you have to instead look into the compiler to find the supporting framework for this collection of functions?

This leads to an even more general question: How much of Haskell is supported by Haskell itself, through type and function definitions, declarations etc; and how much is supported by the compiler/implementation? (I am aware that GHC was written in Haskell, that doesn't answer the question)

That is, if you were to abandon the standard libraries (including the prelude) and do everything from the ground up in raw Haskell; would it be possible to build a complete implementation that has all the features of GHC, using only that minimal set of features? What are the mimimum set of language features that you need in order to build a haskell implementation using Haskell? Would I be able to abandon the prelude and then completely rebuild it manually from within GHC? If you abandon the prelude and never import anything, what is left over for you to work with?

It may seem like I'm asking a million questions, but they're really all trying to ask the same thing with different wording. Give it your best shot SO!

like image 912
TheIronKnuckle Avatar asked Aug 17 '11 00:08

TheIronKnuckle


1 Answers

Alas, there is no magic in the tuples. Here's the implementation GHC uses, and to give you some idea of what's going on here's the source for the last definition:

data (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) a b c d e f g h i j k l m n o p q r s t u v w x y z a_ b_ c_ d_ e_ f_ g_ h_ i_ j_ k_ l_ m_ n_ o_ p_ q_ r_ s_ t_ u_ v_ w_ x_ y_ z_ a__ b__ c__ d__ e__ f__ g__ h__ i__ j__
  = (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) a b c d e f g h i j k l m n o p q r s t u v w x y z a_ b_ c_ d_ e_ f_ g_ h_ i_ j_ k_ l_ m_ n_ o_ p_ q_ r_ s_ t_ u_ v_ w_ x_ y_ z_ a__ b__ c__ d__ e__ f__ g__ h__ i__ j__

...yeah.

So, would it be possible to define this family of operators/functions from within the haskell implementation itself, using nothing but the type system and existing language features (declarations, type signatures, function definitions etc.)? And if so, how? Or is it impossible and you have to instead look into the compiler to find the supporting framework for this collection of functions?

No, there's no way to define the tuples like that in a generic way. The common pattern is purely syntactic, nothing that can be done recursively in the type system or otherwise. You could generate such definitions using Template Haskell, certainly, but you'd still be generating each individually with string manipulation to create the name, not using any sort of shared structure.

There's also the matter that tuple syntax is built-in and not something that can be imitated, but that's a separate issue. You might imagine types like:

data Tuple2 a b = Tuple2 a b
data Tuple3 a b c = Tuple3 a b c

...etc., which don't use special syntax but still can't be defined generically for the reasons above.

This leads to an even more general question: How much of Haskell is supported by Haskell itself, through type and function definitions, declarations etc; and how much is supported by the compiler/implementation? (I am aware that GHC was written in Haskell, that doesn't answer the question)

Almost all of it is defined in Haskell. Certain things have special syntax you can't imitate, but in most cases that only extends as far as the compiler giving special attention to certain definitions. Otherwise, there's no difference between this:

data [] a = [] | a : [a]

...and any equivalent type you define yourself.

That is, if you were to abandon the standard libraries (including the prelude) and do everything from the ground up in raw Haskell; would it be possible to build a complete implementation that has all the features of GHC, using only that minimal set of features? What are the mimimum set of language features that you need in order to build a haskell implementation using Haskell? Would I be able to abandon the prelude and then completely rebuild it manually from within GHC? If you abandon the prelude and never import anything, what is left over for you to work with?

You may find it enlightening to read about GHC's NoImplicitPrelude and RebindableSyntax extensions, which let you, among other things, change the definitions used to interpret do notation, how numeric literals are handled, what the if then else syntax does, etc.

Suffice it to say that very, very little can't be reimplemented. Most things that can't are only special due to syntax, and could be replaced with equivalent stuff (like lists and tuples, above).

In the end there's a limited set of things that have very special behavior--the IO type being an obvious example--that you can't replace at all, because they're hooked directly into something in the runtime system that you can't replace.

like image 122
C. A. McCann Avatar answered Oct 12 '22 09:10

C. A. McCann