2013-02-19 4 views
2

Простой класс с flatMap/карта, которая не делает ничего, но лениво хранить значение:Как идиоматически итеративно flatMap коллекция против своих членов?

[Note1: этот класс может быть заменен любого класса с flatMap/карты. Вариант - это только один конкретный пример, этот вопрос относится к общему случаю]

[Примечание2: scalaz - интересная библиотека, но этот вопрос не относится к ней. Если нет станд Scala решение библиотеки, кроме того, что я писал ниже, что является приемлемым]

class C[A](value : => A) { 
    def flatMap[B](f: A => C[B]) : C[B] = { f(value) } 
    def map[B](f: A => B) : C[B] = { new C(f(value)) } 
    override def toString = s"C($value)" 
} 
object C { 
    def apply[A](value : => A) = new C[A](value) 
} 

Функция, которая итеративно применяется flatMap к своим членам:.

def invert[A](xs: Traversable[C[A]], acc: List[A] = Nil) : C[List[A]] = 
    if(xs.nonEmpty) { 
    xs.head flatMap { a => invert(xs.tail, a :: acc) } 
    } else { 
    C(acc.reverse) 
    } 

функции в действии:

scala> val l = List(C(1),C(2),C(3)) 
l: List[C[Int]] = List(C(1), C(2), C(3)) 

scala> invert(l) 
res4: C[List[Int]] = C(List(1, 2, 3))  

Есть ли способ переписать «инвертировать» идиоматически? Кроме того, есть ли функциональный «глагол», который фиксирует то, что я здесь делаю?

+1

возможно дубликат [Преобразование списка опций на вариант списка с помощью Scalaz] (http://stackoverflow.com/questions/2569014/convert-a-list-of- опции-к-с-вариант-из-списка, использующих-scalaz). Не совсем тот же вариант использования, но ожидаемый результат тот же. – sschaef

+0

Непонятно, что у кого-то есть намерение, когда в представленном коде есть несколько (5) ошибок компиляции ... –

+0

Я бы хотел избежать решения scalaz, спасибо. Если нет идиоматического решения scala, это приемлемый ответ. – lancegatlin

ответ

1

Проблема с вашим решением является то, что он даст переполнение стека для больших списков, как это полностью (не только хвост) рекурсивный. Я бы вместо того, чтобы сложить:

def invert[A](xs: Traversable[C[A]]) = 
    (C(List[A]()) /: xs){ (c,x) => c.flatMap(l => x.map(_ :: l)) }.map(_.reverse) 
0

Вы можете сделать invert немного яснее спичкой шаблона, но это по сути тот же код:

xs match { 
    case x0 :: xMore => x0.flatMap(a => invert(xMore, a :: acc)) 
    case Nil => C(acc.reverse) 
} 
Смежные вопросы