很多人问Ceylon是否会有元组。嗯,我想,为什么不呢?编写以下通用代数数据类型很容易
shared interface TupleOrUnit<P...> of Tuple<P...> | unit {} //note: depends upon support for GADTs
shared class Tuple<T,P...>(T head, TupleOrUnit<P...> tail) satisfies TupleOrUnit<T,P...> { shared T head = head; shared TupleOrUnit<P...> tail = tail; }
shared object unit extends Case("unit") satisfies TupleOrUnit<> {}
请注意,这里TupleOrUnit的定义依赖于编译器对通用代数数据类型(GADTs)的支持,因为子句中的类型不涵盖P...的每一个可能的参数列表...。我们正在尝试让编译器推断出Tuple.tail的类型是Tuple当有多个类型参数时。即使我们没有对GADTs的支持,我们也可以通过删除子句中的类型不涵盖P...子句,并添加一个引入,来获得元组支持。这是一个稍微有些丑陋的解决方案,但不会影响客户端。无论如何,代码最终看起来像这样TupleOrUnit无论如何,无论我们选择哪条路径,现在你都可以创建一个这样的元组
shared interface TupleOrUnit<P...> {}
shared class Tuple<T,P...>(T head, TupleOrUnit<P...> tail) satisfies TupleOrUnit<T,P...> { shared T head = head; shared TupleOrUnit<P...> rest = tail; }
shared object unit satisfies TupleOrUnit<> {}
shared interface TupleTail adapts Tuple<T,P...> { shared Tuple<P...> tail { if (is Tuple<P...> rest) { return rest; } else { //someone else extended TupleOrUnit directly throw Exception("unexpected subtype of TupleOrUnit"); } } }
并且可以像这样访问它的元素
local labeledPosition = Tuple(x,Tuple(y,Tuple(label,unit))); //inferred type Tuple<Float,Float,String>
嗯,这有点啰嗦,所以我们可能需要添加一些方便的函数来处理成对和三联组
Float x = labeledPosition.head; Float y = labeledPosition.tail.head; String name = labeledPosition.tail.tail.head;
这让我们可以将上面的示例简化为
shared Tuple<X,Y> pair<X,Y>(X x, Y y) { return Tuple(x,Tuple(y,unit)); } shared Tuple<X,Y,Z> triple<X,Y,Z>(X x, Y y, Z z) { return Tuple(x, pair(y,z)); } shared T first<T,P...>(Tuple<T,P...> tuple) { return tuple.head; } shared T second<S,T,P...>(Tuple<S,T,P...> tuple) { return tuple.tail.head; } shared T third<R,S,T,P...>(Tuple<R,S,T,P...> tuple) { return tuple.tail.tail.head; }
现在,这一切都很合理,也许我们可以将此类代码作为语言模块的一部分提供,但事实是,这并不是人们所要求的。他们想要的是糖。为了使元组足够方便而值得使用,我认为你真的需要在语言定义中对它们提供一些额外的语法支持
local labeledPosition = triple(x,y,label);
Float x = first(labeledPosition); Float y = second(labeledPosition); String name = third(labeledPosition);
使用简化语法实例化它们的更方便的方法
- 在方法参数列表、循环中以及可能甚至在规范语句的左侧支持解构元组
local labeledPosition = (x,y,label);
- 编写元组类型的缩写语法......
for ((Float x, Float y, String label) in labeledPositions) { ... }
(Float x, Float y, String label) = labeledPosition;
- ...
(Float,Float,String) labeledPosition;
嗯,这为语言功能添加了大量的额外语法,在我看来,在Ceylon这样的面向对象语言中,这个功能的价值相当有限。我的意思是,我可以看到一些合理的泛型对和三联组的用例,但我真的不认为我们应该鼓励人们编写返回4元组的代码。
对于表示某种关联数组的条目对的特殊情况,我们确实已经有了特殊的语法糖。条目,具有
- 方便的->实例化它们的运算符,以及
- 方法参数列表和...循环中的解构支持。
因此,我认为这个特性并不值得增加额外的复杂性。这仅仅是一个额外的学习点,而且这个特性很容易被误用。但是,我保留在未来某个时候改变看法的权利!