#lang scheme

(require mzlib/trace)
(require srfi/41)

(define N
  (stream-cons 0
               (stream-map add1 N)))


(define serie
  (stream-lambda (f x)
    (stream-cons x (serie f (f x))) ))

;(trace serie)

(define-syntax sucesivamente
  (syntax-rules ()
    ((sucesivamente x)
     (list 
      (list 'lista.naturales (list 'add1 (sub1 x))))) ))

(define lista.naturales
  (lambda (n to-n+j)
    (letrec
        ((suspensivos (list (string->symbol "...")))
         (naturales (serie (lambda (y) (add1 y)) n));(serie add1 n));
         (aux
          (lambda (s x i)
            (if (= i 0)
                (sucesivamente x)
                (cons (stream-car s)
                      (aux (stream-cdr s) (add1 x) (sub1 i)))) ))
         )
      (aux naturales n to-n+j) )))
(define serie-nat (serie add1 1))

(define fibo
  (stream-cons 0
               (stream-cons 1
                            (stream-map +
                                        fibo
                                        (stream-cdr fibo)))))

(define una-serie
  (lambda (desde hasta serie)
    (letrec
        ((suspensivos (list (string->symbol "...")))
         (n-serie serie)
         (aux0
          (lambda (s i j)
            (if (= i j)
                s
                (aux0 (stream-cdr s) (add1 i) j))))
         (aux
          (lambda (s d h)
            (if (> d h)
                suspensivos
                (cons (stream-car s)
                      (aux (stream-cdr s) (add1 d) h))) ))
         )
      (aux (aux0 n-serie 1 desde) 1 hasta) )))

;;;;;;;;;;;;;;;;
(define bajo-demanda
  (lambda (s)
    (do
        ((letra #\s)
         (resultado '())
         (tick-s s))
      ((char=? letra #\n) (reverse resultado))
      (set! resultado (cons (stream-car tick-s) resultado))
      (set! tick-s (stream-cdr tick-s))
      (set! letra (read-char)) ) ))

(define natur
  (lambda (n)
    (add1 n)))

(define n-esimo-nat
  (lambda (n)
    (letrec ((aux
              (lambda (x n)
                (if (= n 0)
                    x
                    (aux (add1 x) (sub1 n))))))
      (aux 0 n)) ))

(define n-esimo-fib
  (lambda (n)
    (if (or (= n 0) (= n 1))
        n
        (+
         (n-esimo-fib (- n 1))
         (n-esimo-fib (- n 2)))) ))

(define nat
  (serie add1 0))
;  (stream-cons 0 (nat add1 (add1 0))) )

(define n-esimo
  (lambda (serie ord)
    (if (= ord 0)
        (stream-car serie)
        (n-esimo (stream-cdr serie) (sub1 ord))) ))

;; SRFI/41

;(define s (stream-from -1))
;(una-serie 1 30 s)
;(define w (stream-from 1 2))
;(una-serie 1 30 w)

(define to_nat 
  (stream-lambda (base proc) 
    (stream-cons 
     base 
     (to_nat (proc base) proc))))

(define fibonacci
  (stream-cons 0
   (stream-cons 1
    (stream-map + (stream-cdr fibonacci) fibonacci))))
               

(define mi-proc
  (lambda (proc s1 s2)
    (if (or (stream-null? s1) (stream-null? s2))
        stream-null
        (stream-cons
         (proc
          (stream-car s1)
          (stream-car s2))
         (mi-proc proc (stream-cdr s1) (stream-cdr s2)))) ))

(define to_fibo
  (stream-lambda (stream)
    (stream-cons
     (stream-car stream)
     (stream-cons
      (stream-car (stream-cdr stream))
      stream-null)) ))

;to_nat

;(define naturales (to_nat 0 add1))
;naturales
;(stream->list (stream-take 20 naturales))

(define serie-negativos
  (stream-lambda (base)
   (stream-cons base (serie-negativos (sub1 base))) ))       

(define-stream (stream-member pred-igualdad? obj stream)
  (stream-let loop ((strm stream))
    (cond ((stream-null? strm) #f)
          ((pred-igualdad? obj (stream-car strm)) strm)
          (else (loop (stream-cdr strm)))) ) )