2015-02-04 4 views
2

Я пытаюсь переписать следующий пример из книги «Структура и интерпретация компьютерных программ», глава 3.5.4: http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-24.html#%_sec_3.5.4Правильное использование отсроченной оценки в Scala

Ниже приведены мои коды:

def addStream(s1 : Stream[Double], s2 : Stream[Double]) : Stream[Double] = { 
    (s1.head + s2.head) #:: addStream(s1.tail, s2.tail) 
} 

def scaleStream(stream : Stream[Double], factor : Double) : Stream[Double] = { 
    (stream.head * factor) #:: scaleStream(stream.tail, factor) 
} 

def integral(integrandLazy: => Stream[Double], initialValue : Double, dt : Double) : Stream[Double] = { 
    def int : Stream[Double] = { 
    initialValue #:: addStream(scaleStream(evalStream, dt), int) 
    } 
    def evalStream : Stream[Double] ={ 
    lazy val stream : Stream[Double] = integrandLazy 
    stream 
    } 
    int 
} 

def solve(f : Double => Double, y0 : Double, dt : Double) : Stream[Double] = { 
    def y : Stream[Double] = { 
    integral(dy, y0, dt) 
    } 
    def dy : Stream[Double] = { 
    y.map(f) 
    } 
    y 
} 

val returnedStream = solve((x : Double) => {x}, 1, 0.001) 
val limited = returnedStream take 30 
limited foreach println 

Итак, вы можете видеть, что я пытаюсь использовать функцию ленивого значения в Scala, чтобы подражать задерживаемой оценке в книге. Программа запускается, но она застревает, когда она пытается оценить 24-й элемент в потоке.

Что случилось с моей программой? Использую ли я правильную функцию в Scala для имитации задержек?

ответ

1

В Scala, lazy val s оценивается, как только вы упоминаете им. Таким образом, в вашем примере это ничего не делает, поскольку вы упоминаете это сразу после его определения.

По сути, вы можете перевести lazy val следующим образом (фактический перевод посложнее, потому что заботится о вопросах многопоточности, но никогда не забывайте, что здесь):

def evalStream: Stream[Double] = { 
    var _stream: Stream[Double] = null 
    var _streamInit: Boolean = false 
    def stream: Stream[Double] = { 
    if (!_streamInit) { 
     _stream = integrandLazy 
     _streamInit = true 
    } 
    _stream 
    } 
    stream 
} 

С этого переписывания, должно быть ясно, что все это в основном эквивалентно просто оценке integrandLazy с нетерпением.

+0

Спасибо за ваш ответ! Я использовал ваш код, но это не решает проблему. Такое же поведение по-прежнему сохраняется - оно печатает первые 24 числа (вокруг этого), а затем зависает программа. Я попытался пройти через программу (используя IntelliJ здесь), я вижу там какую-то странную рекурсию. Как вы также упоминаете о проблемах с потоками - может быть, это смесь проблемы потоковой/рекурсии, вызванной этим кодом? В любом случае, коды в моем вопросе могут быть легко запущены в приложении, расширяющем приложение - пожалуйста, попробуйте также! :) Ваша помощь очень ценится! – mpchau

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