2014-12-02 5 views
0

У меня есть API-интерфейс сервера, который возвращает список вещей и делает это в кусках, скажем, по 25 элементов за раз. С каждым ответом мы получаем список элементов и «токен», которые мы можем использовать для следующего вызова сервера, чтобы вернуть следующие 25 и т. Д.Преобразование thunk в последовательность после итерации

Обратите внимание, что мы используем клиентскую библиотеку, написанную на устаревшей старой изменчивой Java, и не подходим ко всем функциональным композиционным шаблонам Scala.

Я ищу способ вернуть лениво оцененную последовательность всех элементов сервера, выполнив вызов сервера с последним токеном всякий раз, когда локальный список элементов исчерпан. До сих пор я знаю:

def fetchFromServer(uglyStateObject: StateObject): Seq[Thing] = { 
    val results = server.call(uglyStateObject) 

    uglyStateObject.update(results.token()) 

    results.asScala.toList ++ (if results.moreAvailable() then 
     fetchFromServer(uglyStateObject) 
    else 
     List()) 
} 

Однако эта функция действительно требует оценки. То, что я ищу, заключается в том, чтобы ++ конкатенировать «строгую последовательность» и «ленивую последовательность», где thunk будет использоваться для извлечения следующего набора элементов с сервера. В сущности, я хочу что-то вроде этого:

results.asScala.toList ++ Seq.lazy(() => fetchFromServer(uglyStateObject)) 

Только я не знаю, что использовать вместо Seq.lazy.

Вещи, которые я видел до сих пор:

  • SeqView, но я видел комментарии, что не следует использовать, поскольку он переоценивает все время?
  • Потоки, но они кажутся, что абстракция должна генерировать элементы за раз, тогда как я хочу генерировать кучу элементов за раз.

Что следует использовать?

+0

Я бы порекомендовал использовать поток «Процесс». Это поверхностно ориентировано на одноэлементное представление, но есть очень простой API, который вы можете использовать для испускания куска одновременно. – lmm

ответ

0

Я также предлагаю вам взглянуть на scalaz-strem. Вот небольшой пример того, как это может выглядеть как

import scalaz.stream._ 
    import scalaz.concurrent.Task 

    // Returns updated state + fetched data 
    def fetchFromServer(uglyStateObject: StateObject): (StateObject, Seq[Thing]) = ??? 

    // Initial state 
    val init: StateObject = new StateObject 

    val p: Process[Task, Thing] = Process.repeatEval[Task, Seq[Thing]] { 
    var state = init 
    Task(fetchFromServer(state)) map { 
     case (s, seq) => 
     state = s 
     seq 
    } 
    } flatMap Process.emitAll 
0

В самом деле, в то же время я уже нашел немного другой ответ, который я нахожу более удобным для чтения (на самом деле, используя Streams):

def fetchFromServer(uglyStateObject: StateObject): Stream[Thing] = { 
    val results = server.call(uglyStateObject) 

    uglyStateObject.update(results.token()) 

    results.asScala.toStream #::: (if results.moreAvailable() then 
     fetchFromServer(uglyStateObject) 
    else 
     Stream.empty) 
} 

Спасибо всем за