Scala: как создать тип, параметризованный значением, а не типом - PullRequest
4 голосов
/ 23 августа 2011

Можно ли создать в Scala тип, параметризованный значением?Вместо определения частичного типа List[A] и параметризации его с помощью List[Int], я хотел бы определить частичный тип (в псевдокоде) Element[Symbol] и параметризовать его с помощью Element['td].В этом примере тип представляет элемент XML: Element['td] сообщает средству проверки типа Scala, что у нас есть элемент <td>, и вы можете себе представить, что у него могут быть API, которые специально ожидают или возвращают <td> элементы.

(Подклассы, как в class Td extends Element, не очень удовлетворительное решение, так как не мешают двум частям кода, возможно написанным независимыми разработчиками, объявлять разные подклассы для <td>, которые затем будут рассматриватьсябыть различными типами с помощью проверки типов Scala.)

Ответы [ 4 ]

4 голосов
/ 23 августа 2011

Если вы действительно хотите параметризовать тип по значению, вам нужен язык программирования с зависимой типизацией, такой как Agda.

2 голосов
/ 23 августа 2011

Просто некоторые идеи, с которыми можно поиграть ... Объекты - это значения, и у них есть тип.

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.

1 голос
/ 10 июня 2012

Синглтон-типы дадут вам желаемое,

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 s: любой стабильный идентификатор ссылочного типа порождает уникальный одноэлементный тип, который можно использовать таким же образом.

1 голос
/ 23 августа 2011

Похоже, что вы действительно хотите не столько параметризовать тип по значению (как вы могли бы в 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 не принимает этот синтаксис ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...