是否可以在Scala中创建一个由值参数化的类型?我不想定义部分类型List[A]
并使用List[Int]
对其进行参数化,而是要定义部分类型(在伪代码中)Element[Symbol]
并使用Element['td]
对其进行参数化。在此示例中,类型表示XML元素:Element['td]
通知Scala类型检查器我们有<td>
元素,您可以想象一个人可以拥有特定期望或返回的API {{1} } elements。
(子类化,如在<td>
中,不是一个非常令人满意的解决方案,因为它不会阻止两个代码(可能由独立开发人员编写)声明class Td extends Element
的不同子类,然后,Scala类型检查器会将其视为不同的类型。)
答案 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.Element
与Tr.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
并没有什么特别之处:引用类型的任何稳定标识符都会产生一个独特的单例类型,可以以相同的方式使用。