2016-11-03 3 views
4

Во-первых, позвольте мне извиниться, если мой вопрос неясен. Я еще не совсем понял язык Scala, поэтому я, вероятно, объединяю термины. Я думаю, что мой пример будет более ясным.Как я могу специализировать признак с ограничением типа None?

Я пытаюсь создать признак Hierarchical, который описывает в основном вершины в графе - любой объект, который может иметь список родителей и список детей.

Более конкретно:

  • 1) Hierarchical может или не может иметь родителей.

  • 2) Если это так, то родители Hierarchical.

  • 3) Hierarchical будет иметь детей, которые также Hierarchical.

Вот моя общая черта:

/* 
    Hierarchical takes two type parameters: Parent and Child. 
    These should be Hierarchicals with parameters Parent and Child as well. 
*/ 
trait Hierarchical[Parent <: Hierarchical[Parent, Child], 
        Child <: Hierarchical[Parent, Child]] { 

    // parents must be passed by constructor lest they are treated as None. 
    // (Requirement 1, 2) 
    val parents: Option[List[Hierarchical[Parent, Child]]] = None 

    // children can be added, so mutability needed (Requirement 3) 
    var children: List[Hierarchical[Parent, Child]] = List() 

    def addChild(child: Child) = children ++= List(child) 
} 

специализации на это «корень» вершина, чьи родители не будут существовать, поэтому тип не должен быть указан на всех - константы выглядит , это None. Вот моя попытка специализировать Hierarchical черта:

/* 
    A RootHierarchical has no parents. It does, however, have 
    children whose parents are RootHierarchicals and whose children 
    are Child. 
    A parent can be none (Requirement 1) 
*/ 
trait RootHierarchical[Child <: Hierarchical[RootHierarchical, Child]] 
    extends Hierarchical[None.type, Child] { 
    override val parents = None 
} 

IntelliJ доволен этим, но тест я написал не компиляции:

import org.scalatest.FlatSpec 

class TestHierarchy extends FlatSpec { 

    "A Hierarchical object" should "be constructable" in { 

    /* 
    Create a dummy 
    */ 
    class DummyHierarchical(override val parents: List[DummyParentHierarchical]) 
     extends Hierarchical[DummyParentHierarchical, DummyHierarchical] 

    class DummyParentHierarchical extends RootHierarchical[DummyHierarchical] 

    val dummyParent = new DummyParentHierarchical 
    val dummyChild = new DummyHierarchical(List(dummyParent)) 
    dummyParent.addChild(dummyChild) 

    assert(dummyParent.parents.isEmpty) 
    assert(dummyParent.children.nonEmpty) 
    } 
} 

Ошибка здесь:

Error:(14, 11) type arguments [None.type,Child] do not conform to trait Hierarchical's type parameter bounds [Parent <: Hierarchical[Parent,Child],Child <: Hierarchical[Parent,Child]] 
    extends Hierarchical[None.type, Child] { 

Мой вопрос таков: как я могу создать эту специализацию? Я знаю, что None.type не является типом Hierarchical, но как я могу специализироваться на этом?

+0

Я думаю, что этот вопрос, исходя из вашего определения признака. 'черта Иерархический [Родитель <: Опция [Иерархический [Родитель, Ребенок]], Child <: Иерархическая [Опция [Родитель], Ребенок]]' говорит что-то вроде этого пункта спараметрировано с типом родителя, который является вариант этого признака с теми же родительскими и дочерними типами, что и этот экземпляр, и дочерним типом, который параметризуется опцией parent (которая сама является опцией) и ее собственным типом, что означает, что родительский элемент ребенка является опцией Родитель. –

+0

Я очень рекомендую взглянуть на разговор Роба Норриса о программировании с программированием на основе функциональных баз данных с использованием типов Fixpoint (https://www.youtube.com/watch?v=7xSfLPD6tiQ).В разговоре используется Doobie, но он действительно применим к любой рекурсивной структуре данных. –

+0

@AngeloGenovese Спасибо за видео - очень интересно. Не уверен, что я могу использовать его, потому что он использует теорию категорий, которая в значительной степени опирается на типы. Я полагаюсь на черты; то есть родители и дети могут быть разных типов, если они оба реализуют «Иерархический». – erip

ответ

1

После некоторого «мозгового штурма» я обнаружил, что типы родителей не нужно указывать - они могут быть произвольными Иерархическими типами и будут иметь значение по умолчанию Nil.

Вот моя реализация:

// T is the type of children -- they should be Hierarchicals. 
trait Hierarchical[T <: Hierarchical[T]] { 
    // The parents will be a list of some arbitrary Hierarchical 
    val parents: List[Hierarchical[_]] = Nil 
    var children: List[Hierarchical[T]] = List() 
} 

// Nodes that aren't root nodes will have parents specified by ctor 
class NonRootNode(override val parents: List[Hierarchical[_]]) 
    extends Hierarchical[NonRootNode] {} 

// Roots will have no way to update their parents. 
class Root extends Hierarchical[NonRootNode] { 
    final override val parents = Nil 
} 

Вот небольшой водитель с некоторыми тестами: Ideone it

Смежные вопросы