2015-08-07 1 views
0

Я пытаюсь определить пользовательский список, который, как встроенный List[+A], но гораздо проще:Что самое простое определение MyList.flatten

sealed trait MyList[+A] { 
    def flatMap[B](f: A => MyList[B]): MyList[B] 
    def map[B](f: A => B): MyList[B] 
    def flatten[B](implicit asTraversable: A => GenTraversableOnce[B]): MyList[B] 
} 


case object MyNil extends MyList[Nothing] { 
    override def flatMap[B](f: (Nothing) => MyList[B]): MyList[B] = ??? 
    override def flatten[B](implicit asTraversable: (Nothing) => GenTraversableOnce[B]): MyList[B] = ??? 
} 

case class MyCons[A](head: A, tail: MyList[A]) extends MyList[A] { 
    override def flatMap[B](f: (A) => MyList[B]): MyList[B] = ??? 
    override def flatten[B](implicit asTraversable: (A) => GenTraversableOnce[B]): MyList[B] = ??? 
} 

Проблема заключается в том, что я не уверен, как определить метод flatten. Я скопировал неявное значение asTraversable откуда-то:

def flatten[B](implicit asTraversable: A => GenTraversableOnce[B]): MyList[B] 

Но не знаю, как осуществить это, даже не уверен, что это правильно.

Как сделать заказной список flatten в состоянии простейшей защиты?

+0

Подумайте, как вы хотите, чтобы Flatten действовал, в случае, когда тип списка не является чем-то, что имеет смысл сгладить. например что произойдет, если вы назовете «List [Int] .flatten'? – mattinbits

+0

@mattinbits В этой проблеме я не могу справиться. Не обязательно делать это только «flatten'able для« List [T [_]] ', где« T »является обходной – Freewind

+0

Для обычного списка scala вы получаете ошибку времени компиляции для« List (1,2,3) .flatten' Если вы ищете более простой подход, вы можете сделать это исключение во время выполнения и проверить, является ли тип вашего списка Traversable при вызове сглаживания. Тогда вам не нужен GenTraversableOnce в подписи – mattinbits

ответ

1

Самый простой способ, вероятно, определить метод fromTraversable где-то, возможно, в объекте компаньона:

object MyList { 
    def fromTraversable[T](t: Traversable[T]): MyList[T] = 
    if (t.isEmpty) MyNil 
    else MyCons(t.head, fromTraversable(t.tail)) 
} 

Этот метод обычно может быть полезным для реализации списка в любом случае.

А потом flatten просто вызов flatMap (вам необходимо реализовать flatMap, конечно):

sealed trait MyList[+A] { 
    def flatMap[B](f: A => MyList[B]): MyList[B] = ??? 
    def flatten[B](implicit ev: A <:< Traversable[B]): MyList[B] = 
    flatMap(MyList.fromTraversable(_)) 
} 

неявный параметр ev:

  • делает эту ошибку компиляции для вызова flatten на любом другом месте, кроме MyList от Traversable;
  • предоставляет неявное преобразование от A до Traversable[B]. Это преобразование применяется к аргументу MyList.fromTraversable.