Scala:如何创建由值而不是类型参数化的类型

时间:2011-08-23 01:39:23

标签: scala

是否可以在Scala中创建一个由值参数化的类型?我不想定义部分类型List[A]并使用List[Int]对其进行参数化,而是要定义部分类型(在伪代码中)Element[Symbol]并使用Element['td]对其进行参数化。在此示例中,类型表示XML元素:Element['td]通知Scala类型检查器我们有<td>元素,您可以想象一个人可以拥有特定期望或返回的API {{1} } elements。

(子类化,如在<td>中,不是一个非常令人满意的解决方案,因为它不会阻止两个代码(可能由独立开发人员编写)声明class Td extends Element的不同子类,然后,Scala类型检查器会将其视为不同的类型。)

4 个答案:

答案 0 :(得分:4)

如果您真的想通过值参数化类型,则需要依赖类型的编程语言,例如Agda。

答案 1 :(得分:2)

只是一些想法...对象是值,他们有一个类型。

trait XmlElement
object Td extends XmlElement

然后,您可以使用参数化类并在特定类型上使用它。

class Element[T <: XmlElement] { ... }
val elementOnTd = new Element[Td.type]
// elementOnTd can only be used with Td.

如果您只想支持固定数量的元素,那么您可以制作一个密封的特征,而您的图书馆只能使用这些对象(虽然这看起来非常有限)

sealed trait XmlElement
object Td extends XmlElement
object Tr extends XmlElement
// can't have anything other than `Td` and `Tr` !

您可以使用的另一件事是内部类对象不具有相同的类型。因此,您也可以在object Td { class Element { ... } }行中执行某项操作,Td.ElementTr.Element的类型不同。

答案 2 :(得分:1)

听起来你真正想要的不是通过一个值来参数化一个类型(就像你在C ++中那样),而是迫使各个开发人员就一个共同的实现达成一致。

我认为这不是语言为您解决的问题。即使你强迫那里只有一种<td>类型的方式,那么<td>类型究竟是什么呢?

如果您确实想要通过值参数化类型,则可能需要执行以下操作:

object TD {
}

即使它实际上是一个类型,现在你可以写Element[TD]。虽然这仍然存在其他人可以在另一个包中写object TD { }并且有两个包的问题。

您可以尝试使用

之类的东西模拟完全依赖类型
object A { }
object B { }
object C { }
...

object TyString[Car,Cdr] { }

因此“TD”将表示为

TyString[T,TyString[D,()]]

但你可能不想去那里;)

(我听说Scala会实现一些叫做“单例文字”的东西,但这种情况有没有发生?你原本应该写"td".type,但Scala 2.9.1不接受那个语法)。

答案 3 :(得分:1)

单身人士类型会让你想要,

scala> class Element[+T]
defined class Element

scala> val td = 'td
td: Symbol = 'td

scala> val p = 'p
p: Symbol = 'p

scala> def acceptAll[T](e : Element[T]) = e
acceptAll: [T](e: Element[T])Element[T]

scala> def acceptTd(e : Element[td.type]) = e
acceptTd: (e: Element[td.type])Element[td.type]

scala> acceptAll(new Element[p.type])       // OK
res3: Element[Symbol] = Element@628b54f4

scala> acceptAll(new Element[td.type])      // OK
res4: Element[Symbol] = Element@6e7eee36

scala> acceptTd(new Element[td.type])       // OK
res2: Element[td.type] = Element@547fa706

scala> acceptTd(new Element[p.type])        // Doesn't compile
<console>:12: error: type mismatch;
 found   : Element[p.type]
 required: Element[td.type]
              acceptTd(new Element[p.type])
                       ^

然而,他们并没有通过创建一个(密封的)类型族来表示元素名称而给你任何你不可能拥有的东西。请注意,这里使用Scala Symbol并没有什么特别之处:引用类型的任何稳定标识符都会产生一个独特的单例类型,可以以相同的方式使用。