Quote:
But if I try to do a large number of sequences (>600) guile crashes with stack overflow.
|
With guile-2.0 it throws a vm-error instead of outright crashing, and it happens at 8105 instead of 600.
Quote:
Presumably, due to strict evaluation.
|
From a typical scheme perspective this is due to a lack of tail recursion. The naive recursive version has call depth n. The tail recursive version has call depth 1. I
think Haskell doesn't maintain a call stack separate from the heap, so it can't have stack overflow.
Code:
(define fib-tr
(lambda (a b n list)
(if (< n 1)
(reverse! list)
(fib-tr b (+ a b) (- n 1) (cons a list)))))
;;;
scheme@(guile-user)> (fib-tr 1 1 10 '())
$1 = (1 1 2 3 5 8 13 21 34 55)
Quote:
I know there is delay and force (procedures?)
|
delay is a macro (it has to be since it uses a non-standard evaluation order), and force is a procedure.
You can use
delay to return a
promise of a list (of any expression, in fact). However, the builtin display functions don't give a useful output:
Code:
(define fib-lazy
(lambda (a b n)
(if (< n 2)
(delay (cons a '()))
(delay (cons a (fib-lazy b (+ a b) (- n 1)))))))
;;;
scheme@(guile-user)> (fib-lazy 1 1 10)
$2 = #<promise #<procedure 29c2060 at <current input>:14:8 ()>>
You can use
force to extract the value from a
promise, this can be used to create a function that prints the first n values from a
promise of a list:
Code:
(define (print-promised-list promised-list n)
(let* ((list (force promised-list))
(head (car list))
(tail (cdr list)))
(display head)
(display " ")
(cond
((null? tail)
(display "\n"))
((> n 1)
(print-promised-list tail (- n 1)))
(else (display "...\n")))))
;;;
scheme@(guile-user)> (print-promised-list $2 3)
1 1 2 ...
scheme@(guile-user)> (print-promised-list $2 10)
1 1 2 3 5 8 13 21 34 55
To handle longer lists you'll probably want to implement something like Haskell's
drop.
EDIT: Instead of implementing this from scratch,
SRFI 41 "Streams" provides many useful functions for creating and manipulating lazy lists.