LIPS-scheme / lips

Scheme based powerful lisp interpreter in JavaScript
https://lips.js.org
Other
412 stars 33 forks source link

Expressions that have promises are not called in order #100

Closed jcubic closed 3 years ago

jcubic commented 3 years ago

This make calling two function not in sync they are called in parallel:

(define (print-list file)
  (let ((list (--> (fs.promises.readFile file) (toString) (split "\n"))))
    (--> list (forEach (lambda (fn)
                        (if (not (bound? fn))
                            (begin
                               (display fn)
                               (newline))))))))

(begin
  (print-list "file1")
  (print-list "file2"))

just wrapping with promise fix the issue.

(define (print-list file)
  (let ((list (--> (fs.promises.readFile file) (toString) (split "\n"))))
    (new Promise (lambda (next)
                    (--> list (forEach (lambda (fn)
                                        (if (not (bound? fn))
                                            (begin
                                               (display fn)
                                               (newline))))))
                    (next)))))

The same happen in browser with fetch. Promise resolving mechanism may require rethinking.

jcubic commented 3 years ago

I'm not sure what the problem is, this works fine:

lips> (define (foo arr)
        (let ((x (new Promise (lambda (resolve)
                                 (setTimeout (lambda ()
                                                (print "x")
                                                (resolve arr))
                                             1000)))))
          (--> x (forEach (lambda (x) (print x))))))
lips> (begin
        (foo (list->vector (range 10)))
        (print "done")
        (foo (list->vector (range 10)))
        (print "done"))
x
0
1
2
3
4
5
6
7
8
9
done
x
0
1
2
3
4
5
6
7
8
9
done
jcubic commented 3 years ago

The problem was that JavaScript forEach don't return a value. Here is use case:

(define (p time value)
  (new Promise (lambda (resolve)
                 (setTimeout (lambda ()
                               (resolve value))
                             time))))

(define (foo arr)
  (let ((x (p 1000 arr)))
    (--> x (forEach (lambda (x)
                      (if (p 100 #t)
                          (print x)))))))
(begin
  (foo (list->vector (range 10)))
  (print "done")
  (foo (list->vector (range 10)))
  (print "done"))

This doesn't work, but if you change forEach with a map it works fine and expressions are in sync. The reason why the original code was not working was that bound? was returning a promise that was ignored.

This requires documentation.

jcubic commented 3 years ago

The case documented at Wiki 1.0 Draft