42

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!

4

1 回答 1

45

唉,元组中没有魔法。这是 GHC 使用的实现,为了让您了解发生了什么,这里是最后一个定义的来源:

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__

...是的。

那么,是否有可能从 haskell 实现本身中定义这一系列运算符/函数,只使用类型系统和现有语言特性(声明、类型签名、函数定义等)?如果是这样,怎么办?或者它是不可能的,您必须查看编译器来找到这个函数集合的支持框架?

不,没有办法以通用的方式定义这样的元组。通用模式是纯语法的,在类型系统或其他方式中不能递归地完成任何事情。当然,您可以使用 Template Haskell 生成这样的定义,但您仍然会使用字符串操作单独生成每个定义以创建名称,而不是使用任何类型的共享结构。

还有一个问题是元组语法是内置的,不是可以模仿的,但这是一个单独的问题。您可能会想象以下类型:

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

...等,它们不使用特殊语法,但由于上述原因仍不能通用定义。

这就引出了一个更普遍的问题:Haskell 本身支持多少 Haskell,通过类型和函数定义、声明等;编译器/实现支持多少?(我知道 GHC 是用 Haskell 编写的,这不能回答问题)

几乎所有这些都是在 Haskell 中定义的。某些事物具有您无法模仿的特殊语法,但在大多数情况下,它只会扩展到编译器特别注意某些定义。否则,这之间没有区别:

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

...以及您自己定义的任何等效类型。

也就是说,如果您要放弃标准库(包括前奏曲)并在原始 Haskell 中从头开始做所有事情;是否有可能构建一个具有 GHC 的所有功能的完整实现,只使用最少的功能集?为了使用 Haskell 构建一个 Haskell 实现,您需要最少的语言特性集是什么?我可以放弃前奏,然后在 GHC 中手动完全重建它吗?如果你放弃前奏,从不导入任何东西,那么你还有什么可做的呢?

您可能会发现阅读 GHC 的NoImplicitPrelude 和 RebindableSyntax扩展很有启发性,除其他外,您可以更改用于解释do符号的定义、数字文字的处理方式、if then else语法的作用等。

可以说,非常非常少的东西不能被重新实现。大多数不能仅仅因为语法而变得特殊的东西,可以用等效的东西代替(比如上面的列表和元组)。

最后,有一组有限的东西具有非常特殊的行为——IO类型是一个明显的例子——你根本无法替换,因为它们直接连接到运行时系统中你不能替换的东西代替。

于 2011-08-17T00:39:44.007 回答