i have for (for_next_step.rkt) that allow C style for with break and continue.
Example:
Welcome to DrRacket, version 8.14 [cs].
Language: racket, with debugging; memory limit: 8192 MB.
> (require Scheme+/for_next_step)
> (for ((define i 0) (< i 5) (set! i (+ i 1))) (define x 7) (display i) (newline) (break i))
0
> (for ((define i 0) (< i 5) (set! i (+ i 1))) (define x 7) (display i) (newline) (break))
0
> (for ((define i 0) (< i 5) (set! i (+ i 1))) (define x 7) (display i) (continue) (newline) )
01234
> (for ((define i 0) (< i 5) (set! i (+ i 1))) (define x 7) (display i) (newline) )
0
1
2
3
4
> (define res (for ((define i 0) (< i 5) (set! i (+ i 1))) (define x 7) (display i) (newline) (break i)))
0
result arity mismatch;
expected number of values not received
expected: 1
received: 0
>
the code of the module is:
(module for_next_step racket
(provide for
;;for-basic
;;for-next
;;for-basic/break
;;for-basic/break-cont
;;for/break-cont
;;for-each-in
)
(require (only-in racket/base [for for-racket]) ;; backup original Racket 'for'
(for-syntax r6rs/private/base-for-syntax) ; unless : racket-8.14/share/pkgs/errortrace-lib/errortrace/stacktrace.rkt:709:4: identifier-syntax: undefined; cannot reference an identifier before its definition
Scheme+/increment)
(define-syntax for
(lambda (stx)
(syntax-case stx ()
((kwd (init test incrmt) body ...)
(with-syntax ((BREAK (datum->syntax (syntax kwd) 'break))
(CONTINUE (datum->syntax (syntax kwd) 'continue)))
(syntax
(call/cc
(lambda (escape)
(let-syntax ((BREAK (identifier-syntax (escape))))
init
(let loop ()
(when test
(call/cc
(lambda (next)
(let-syntax ((CONTINUE (identifier-syntax (next))))
(let () ;; allow definitions
body ...)))) ; end call/cc
incrmt
(loop))) ; end let loop
))))) ;; close with-syntax
))))
) ; end library
increment.rkt:
(module increment racket
(provide incf
add1)
;; increment variable
;; this is different than add1 in DrRacket
(define-syntax incf
(syntax-rules ()
((_ x) (begin (set! x (+ x 1))
x))))
(define-syntax add1
(syntax-rules ()
((_ x) (+ x 1))))
)
i works well
but i would attempt (break i) to return i as break should call the continuation of the current code but it does not return a value.
As this could be interesting to allow break to send info on the moment (index) it break away from the for loop.
with the help of another galaxie... (the Guilaxie , i mean the Guile scheme community) the solution is:
(define-syntax for
(lambda (stx)
(syntax-case stx ()
((_ (init test incrmt) body ...)
(with-syntax ((BREAK (datum->syntax stx 'break))
(CONTINUE (datum->syntax stx 'continue)))
(syntax
(call/cc
(lambda (escape)
(let ((BREAK escape))
init
(let loop ()
(when test
(call/cc
(lambda (next)
(let ((CONTINUE next))
(let () ;; allow definitions
body ...)))) ; end call/cc
incrmt
(loop))) ; end let loop
))))) ;; close with-syntax
))))
Welcome to DrRacket, version 8.14 [cs].
Language: racket, with debugging; memory limit: 8192 MB.
> (require Scheme+/for_next_step)
> (define res (for ((define i 0) (< i 5) (set! i (+ i 1))) (define x 7) (display i) (newline) (when (= i 2) (break i))))
0
1
2
> (for ((define i 0) (< i 5) (set! i (+ i 1))) (define x 7) (display i) (newline) )
0
1
2
3
4
> (for ((define i 0) (< i 5) (set! i (+ i 1))) (define x 7) (display i) (continue) (newline) )
01234
> res
2
there was no need of kwd , def.rkt or def.scm in Scheme+ works well without it and return and return-rec allow returning a value without problem, this make me find the problem by comparison....
let and let-syntax in the macro should work the same but i have not test it...
This is not directly related to the original question, but if strict R⁶RS compliance is not a requirement, I would use syntax parameters to implement such feature (also available in Guile).
(require racket/stxparam)
(define-syntax-parameter break
(lambda (stx)
(raise-syntax-error 'break "can only be used inside for")))
(define-syntax-parameter continue
(lambda (stx)
(raise-syntax-error 'continue "can only be used inside for")))
(define-syntax for
(lambda (stx)
(syntax-case stx ()
((_ (init test incrmt) body ...)
(syntax
(call/cc
(lambda (escape)
;; In the body we adjust the 'break' keyword so that calls
;; to 'break' are replaced with calls to the escape
;; continuation.
(syntax-parameterize
([break (syntax-rules ()
[(break vals (... ...))
(escape vals (... ...))])])
init
(let loop ()
(when test
(call/cc
(lambda (next)
;; In the body we adjust the 'continue' keyword so that calls
;; to 'continue' are replaced with calls to the escape
;; continuation.
(syntax-parameterize
([continue (syntax-rules ()
[(continue vals (... ...))
(next vals (... ...))])])
(let () ;; allow definitions
body ...)))) ; end call/cc
incrmt
(loop)))))))))))
and here is some examples of use:
Welcome to DrRacket, version 8.14 [cs].
Language: racket, with debugging; memory limit: 8192 MB.
> (require Scheme+/for_next_step)
> (define res (for ((define i 0) (< i 5) (set! i (+ i 1))) (define x 7) (display i) (newline) (when (= i 2) (break i))))
0
1
2
> (for ((define i 0) (< i 5) (set! i (+ i 1))) (define x 7) (display i) (newline) )
0
1
2
3
4
> (for ((define i 0) (< i 5) (set! i (+ i 1))) (define x 7) (display i) (continue) (newline) )
01234
more readable with SRFI 105 curly infix:
Welcome to DrRacket, version 8.14 [cs].
Language: reader SRFI-105, with debugging; memory limit: 8192 MB.
SRFI-105 Curly Infix parser for Racket Scheme by Damien MATTEI
(based on code from David A. Wheeler and Alan Manuel K. Gloria.)
Possibly skipping some header's lines containing space,tabs,new line,etc or comments.
SRFI-105.rkt : number of skipped lines (comments, spaces, directives,...) at header's beginning : 8
Parsed curly infix code result =
(module Racket-SRFI-105-REPL racket (provide (all-defined-out)))
> (require Scheme+/for_next_step)
(require Scheme+/for_next_step)
#<eof>
> (require Scheme+/nfx)
(require Scheme+/nfx)
#<eof>
> (require Scheme+/assignment)
(require Scheme+/assignment)
#<eof>
> (for ((define i 0) {i < 5} {i := i + 1})
(define x 7)
(display {x + i})
(newline)
(when {i = 2}
(break i)))
(for
((define i 0) (< i 5) ($nfx$ i := i + 1))
(define x 7)
(display (+ x i))
(newline)
(when (= i 2) (break i)))
$nfx$ : parsed-args=.#<syntax (:= i (+ i 1))>
7
8
9
2
#<eof>
>
the same works in Guile and only in Scheme that implements stxparams (not Kawa) ,for those the previous solution can be used.
then... i ran my AI code and the neural sine computation show bad results. As the last modification of Scheme+ code was about for/break/continue with stxparams implementation i roll back to the code before stxparams and it worked again.
But for/break/continue seems to work itself in many other codes.
So I tested the Guile version where i used the same implementation of for/break/continue with stxparams and it give good results on the neural sine.
What can we think about that?
i just can stay for the Racket version of Scheme+ to an implementation of for/break/continue that do not use of stxparams.
The code is too big to debug : AI and Scheme+ code is too big, stxparams is not really portable from one scheme to another one, and i will not use it in the future.
I suppose there is some hard problem to understand with the Racket's macro (as it works in Guile) but "macro is hard" and macro which call macros are harder....