Namespace and evaluation

hello,

i try to wrote an infix evaluator with precedence operator (note i'm not the initial author of the infix evaluator so code and comments are not all from me) in my Scheme+ (precedence in operator can remove a lot of {} useless curly bracket in codes), at some point i have my variables quoted , this is important for evaluating for example 'and and 'or that short-circuit the unused expressions and also important for other reason.

But then i must be able to force the evaluation of the quoted variables at some point in code to get the results.

I used namespace and it works in a way , i think if i include code it is ok like in this example:

#lang reader "SRFI-105.rkt"
;;#lang r5rs

;; infix evaluator

(provide (all-defined-out)) ;; export all bindings

;; as $nfx$ will be part of the definition of Scheme+ it is not wise to use it for implementing itself !
;; at some point this would cause infinite recursive load 
(require "../../Scheme-PLUS-for-Racket/main/Scheme-PLUS-for-Racket/Scheme+.rkt")


;; > {5 * 3 + 2}
;; 17

;; > { #t and #f and (begin (display "BAD") (newline) #t)}
;; #f


(define-namespace-anchor a)
(define ns (namespace-anchor->namespace a))

;; can you believe they made && and || special forms??? yes :-) but with advantage of being short-circuited,but i admit it has been a headlock for an infix solution 
;; note: difference between bitwise and logic operator
;; (define (&& a b) (and a b))
;; (define (|| a b) (or a b))


; a list of lists of operators. lists are evaluated in order, so this also
; determines operator precedence
(define infix-operators
  (list
    ;;(list modulo quotient remainder gcd lcm)
    (list '**)
    (list '* '/)
    (list '+ '-)
   
    ; now this is interesting: because scheme is dynamically typed, we aren't
    ; limited to any one type of function
   
    (list '< '> '= '<> '≠ '<= '>=)
    ;;(list &&)
    ;;(list and) ;; does not work because of special form!
    (list 'and)
    ;;(list || ^^)
    ;;(list or)  ;; does not work because of special form!
    (list 'or)
    ))


;; > (define x 3)
;; > (define y -5)
;; > (! 3 * x + (* 5 y) - 7)
;; -23

;;  (define x 3)
;; > (! x * 5 >= 10)
;; #t
;; ($nfx x * 5 >= 10)
;; #t
;; ($nfx$ 3 * x + (* 5 y) - 7)
;; -23

;; > (! #f && (begin (display "BAD") (newline) #t))
;; BAD
;; #f
;;; evaluates `terms` as a basic infix expression
(define (! . terms)
  (if (null? terms) ;; i added this null case but with correct input this should not be necessary
      terms
      (car (!* terms infix-operators #f))))


;; > (define b #f)
;; > ($nfx$ #t and b)
;; #f

;; > ($nfx$ #f and (begin (display "BAD") (newline) #t))
;; #f
;;  { 4 + 3 * 2 - 19 < 0 - 4}
;; #t
(define-syntax $nfx$
  (syntax-rules ()
    
    ((_ term ...) (! (quote term) ...)))) ;; start quoting all the macros,function, symbols ... so we are no more annoyed with macro 'bad syntax' error and also this should (?) keep the 'and and 'or short-circuited functionalities.


;;  (andy (#t #t #t))
;; #t
;; test if short circuited:
;;  (andy (#f (begin (display "BAD") (newline) #t)))
;; #f
(define-syntax andy ;; Warhol :-)
  (syntax-rules ()
    
    ((_ (term ...)) (and (eval term ns) ...)))) ;; as 'and and 'or has been quoted previously but as macro can not be evaluated we need procedures like the macro



(define-syntax ory ;; Oryx ? :-) ,no just call 'or on terms
  (syntax-rules ()
    
    ((_ (term ...)) (or (eval term ns) ...)))) ;; as 'and and 'or has been quoted previously but as macro can not be evaluated we need procedures like the macro



;; evaluate one group of operators in the list of terms
(define (!** terms stack operators odd?)
  
					; why `odd?`? because scheme's list-iteration is forwards-only and
					; list-construction is prepend-only, every other group of operators is
					; actually evaluated backwards which, for operators like / and -, can be a
					; big deal! therefore, we keep this flipped `odd?` counter to track if we
					; should flip our arguments or not

  (define (calc-proc op a b) ;; keep in mind that now the op-erator is quoted !
 
    (define proc (eval op ns))  ;; this only works with procedure, not special form !
    ;;(display "before eval arg")
    (define val-a (eval a ns))
    (define val-b (eval b ns))
    ;;(display "after eval arg")
    (if odd? (proc val-a val-b) (proc val-b val-a)))

  (define (calc-proc-or-macro op a b) ;; keep in mind that now the op-erator is quoted !
    (cond ((eq? op 'and) (andy (a b)))
	  ((eq? op 'or) (ory (a b)))
	  (else (calc-proc op a b))))

  (cond ((null? terms) stack) ; base case
	;; operator we can evaluate -- pop operator and operand, then recurse
	((and (> (length stack) 1) ;; (begin
				   ;;   ;;(display "operators=") (display operators) (newline)
				   ;;   (let* ((op (car stack))
				   ;; 	    (mres (memq op operators)))
				   ;;     ;; (display "op=") (display op) (newline)
				   ;;     ;; (display "mres=") (display mres) (newline) (newline)
	      ;;     mres)))
	      (memq (car stack) operators))
	      
	 (let ((op (car stack))
	       (fst (car terms))
	       (snd (cadr stack)))
	   ;;(display "op=") (display op) (newline)
	   (!** (cdr terms)
		(cons (calc-proc-or-macro op fst snd) (cddr stack))
		operators
		(not odd?))))
	
	;; otherwise just keep building the stack
	(else (!** (cdr terms)
		   (cons (car terms) stack)
		   operators
		   (not odd?)))))

;; evaluate a list of groups of operators in the list of terms
(define (!* terms operator-groups odd?)
  (if (or (null? operator-groups) ; done evaluating all operators
	  (null? (cdr terms)))    ; only one term left
      terms ; finished processing operator groups
      ;; evaluate another group -- separating operators into groups allows
      ;; operator precedence
      (!* (!** terms '() (car operator-groups) odd?)
	  (cdr operator-groups)
	  (not odd?))))




;; ; also works for inequalities!

;; { 4 + 3 * 2 - 19 < 0 - 4}

;; { #f and (begin (display "BAD") (newline) #t)}

;; (define x 5)
;; ($nfx$ 3 * x)

(define x 7)
(eval 'x ns)

then i can evaluate:

> {3 * x + 1}
22

but when i'm in a module like in this code:


;; this is the bootstrap file for λογικι+ (LOGIKI)

;; Damien Mattei

;; november 2022


;; Note: you can start the code directly from racket/logiki+.rkt if you want. (because include can not be used directly in SRFI-105 REPL for Racket)

(provide (all-defined-out)) ;; export all bindings


(require "../Scheme-PLUS-for-Racket/main/Scheme-PLUS-for-Racket/Scheme+.rkt")

(require "racket/logiki+.rkt")

; DrRacket does not like greek names in filenames
;(include "program-λογικι-2.8.scm")


;; test
;;(define λογικι #t)


;; (infix-symb-min-dnf '{{(not a) and (not b) and (not c) and (not d)} or {(not a) and (not b) and (not c) and d} or {(not a) and (not b) and c and (not d)} or {(not a) and b and (not c) and d} or {(not a) and b and c and (not d)} or {(not a) and b and c and d} or {a and (not b) and (not c) and (not d)} or {a and (not b) and (not c) and d} or {a and (not b) and c and (not d)} or {c and (not d)}} )

;; '((¬b ∧ ¬c) ∨ (c ∧ ¬d) ∨ (¬a ∧ b ∧ d))



;; (infix-symb-min-dnf '(or (and (not a) (not b) (not c) (not d)) (and (not a) (not b) (not c) d) (and (not a) (not b) c (not d)) (and (not a) b (not c) d)  (and (not a) b c (not d))  (and (not a) b c d)  (and a (not b) (not c) (not d)) (and a (not b) (not c) d)  (and a (not b) c (not d))   (and c (not d))))

;; '((!b ^ !c) v (c ^ !d) v (!a ^ b ^ d))

(define-namespace-anchor ankh)
(define ns (namespace-anchor->namespace ankh))

(display "start-... : ns =") (display ns) (newline)

{x <+ 7}

(display "start-... : x =") (display x) (newline)

(eval 'x ns)


;;{x <- 5 + 4}

i then got an error because 'x can be evaluated:

Welcome to DrRacket, version 8.7 [cs].
Language: reader "racket/SRFI-105.rkt" [custom]; memory limit: 8192 MB.
'()
start-... : ns =#<namespace:"/Users/mattei/Dropbox/git/library-FunctProg/start-λογικι-racket+.scm">
7
start-... : x =7
7
> {x <- 5 + 4}
!* : terms = (x <- 5 + 4)
!* : operator-groups = ((**) (* /) (+ -) (< > = <> ≠ <= >=) (and) (or) (<-) (<+))
!** : terms = (x <- 5 + 4)
!** : operators = (**)
!** : stack = ()
!** : odd? = #f
!** : terms = (<- 5 + 4)
!** : operators = (**)
!** : stack = (x)
!** : odd? = #t
!** : terms = (5 + 4)
!** : operators = (**)
!** : stack = (<- x)
!** : odd? = #f
operators=(**)
op=<-
mres=#f

!** : terms = (+ 4)
!** : operators = (**)
!** : stack = (5 <- x)
!** : odd? = #t
operators=(**)
op=5
mres=#f

!** : terms = (4)
!** : operators = (**)
!** : stack = (+ 5 <- x)
!** : odd? = #f
operators=(**)
op=+
mres=#f

!** : terms = ()
!** : operators = (**)
!** : stack = (4 + 5 <- x)
!** : odd? = #t
!* : terms = (4 + 5 <- x)
!* : operator-groups = ((* /) (+ -) (< > = <> ≠ <= >=) (and) (or) (<-) (<+))
!** : terms = (4 + 5 <- x)
!** : operators = (* /)
!** : stack = ()
!** : odd? = #t
!** : terms = (+ 5 <- x)
!** : operators = (* /)
!** : stack = (4)
!** : odd? = #f
!** : terms = (5 <- x)
!** : operators = (* /)
!** : stack = (+ 4)
!** : odd? = #t
operators=(* /)
op=+
mres=#f

!** : terms = (<- x)
!** : operators = (* /)
!** : stack = (5 + 4)
!** : odd? = #f
operators=(* /)
op=5
mres=#f

!** : terms = (x)
!** : operators = (* /)
!** : stack = (<- 5 + 4)
!** : odd? = #t
operators=(* /)
op=<-
mres=#f

!** : terms = ()
!** : operators = (* /)
!** : stack = (x <- 5 + 4)
!** : odd? = #f
!* : terms = (x <- 5 + 4)
!* : operator-groups = ((+ -) (< > = <> ≠ <= >=) (and) (or) (<-) (<+))
!** : terms = (x <- 5 + 4)
!** : operators = (+ -)
!** : stack = ()
!** : odd? = #f
!** : terms = (<- 5 + 4)
!** : operators = (+ -)
!** : stack = (x)
!** : odd? = #t
!** : terms = (5 + 4)
!** : operators = (+ -)
!** : stack = (<- x)
!** : odd? = #f
operators=(+ -)
op=<-
mres=#f

!** : terms = (+ 4)
!** : operators = (+ -)
!** : stack = (5 <- x)
!** : odd? = #t
operators=(+ -)
op=5
mres=#f

!** : terms = (4)
!** : operators = (+ -)
!** : stack = (+ 5 <- x)
!** : odd? = #f
operators=(+ -)
op=+
mres=(+ -)

op=+
calc : op = +
calc : a = 4
calc : b = 5
calc : odd? = #f
!** : terms = ()
!** : operators = (+ -)
!** : stack = (9 <- x)
!** : odd? = #t
!* : terms = (9 <- x)
!* : operator-groups = ((< > = <> ≠ <= >=) (and) (or) (<-) (<+))
!** : terms = (9 <- x)
!** : operators = (< > = <> ≠ <= >=)
!** : stack = ()
!** : odd? = #t
!** : terms = (<- x)
!** : operators = (< > = <> ≠ <= >=)
!** : stack = (9)
!** : odd? = #f
!** : terms = (x)
!** : operators = (< > = <> ≠ <= >=)
!** : stack = (<- 9)
!** : odd? = #t
operators=(< > = <> ≠ <= >=)
op=<-
mres=#f

!** : terms = ()
!** : operators = (< > = <> ≠ <= >=)
!** : stack = (x <- 9)
!** : odd? = #f
!* : terms = (x <- 9)
!* : operator-groups = ((and) (or) (<-) (<+))
!** : terms = (x <- 9)
!** : operators = (and)
!** : stack = ()
!** : odd? = #f
!** : terms = (<- 9)
!** : operators = (and)
!** : stack = (x)
!** : odd? = #t
!** : terms = (9)
!** : operators = (and)
!** : stack = (<- x)
!** : odd? = #f
operators=(and)
op=<-
mres=#f

!** : terms = ()
!** : operators = (and)
!** : stack = (9 <- x)
!** : odd? = #t
!* : terms = (9 <- x)
!* : operator-groups = ((or) (<-) (<+))
!** : terms = (9 <- x)
!** : operators = (or)
!** : stack = ()
!** : odd? = #t
!** : terms = (<- x)
!** : operators = (or)
!** : stack = (9)
!** : odd? = #f
!** : terms = (x)
!** : operators = (or)
!** : stack = (<- 9)
!** : odd? = #t
operators=(or)
op=<-
mres=#f

!** : terms = ()
!** : operators = (or)
!** : stack = (x <- 9)
!** : odd? = #f
!* : terms = (x <- 9)
!* : operator-groups = ((<-) (<+))
!** : terms = (x <- 9)
!** : operators = (<-)
!** : stack = ()
!** : odd? = #f
!** : terms = (<- 9)
!** : operators = (<-)
!** : stack = (x)
!** : odd? = #t
!** : terms = (9)
!** : operators = (<-)
!** : stack = (<- x)
!** : odd? = #f
operators=(<-)
op=<-
mres=(<-)

op=<-
calc : op = <-
calc : a = 9
calc : b = x
calc : odd? = #f
calc : ns = #<namespace:"/Users/mattei/Dropbox/git/Scheme-PLUS-for-Racket/main/Scheme-PLUS-for-Racket/Scheme+.rkt">
. . ../Scheme-PLUS-for-Racket/main/Scheme-PLUS-for-Racket/included-files/scheme-infix.rkt:152:0: x: undefined;
 cannot reference an identifier before its definition
> 

you will notice that the ns namesapce variable changed!!!:

start-... : ns =#<namespace:"/Users/mattei/Dropbox/git/library-FunctProg/start-λογικι-racket+.scm"

and at end:

calc : ns = #namespace:"/Users/mattei/Dropbox/git/Scheme-PLUS-for-Racket/main/Scheme-PLUS-for-Racket/Scheme+.rkt"
. . ../Scheme-PLUS-for-Racket/main/Scheme-PLUS-for-Racket/included-files/scheme-infix.rkt:152:0: x: undefined;
cannot reference an identifier before its definition

the namespace seems changing ?!!!

i want a solution to define the namespace in the Scheme+ module , not to include files, i thought that putting the namespace definition and 'provide them would work but not.

any idea?

Damien

Hi Damien,

Is it possible to make a minimal example that shows the problem?

hello Jens,

i made an example:

a main file where i want to be able to add code that rely on stuff developped in module or use it at toplevel:

file maintesteval.rkt :

#lang racket

(provide foo ankh ns)

(require "testevalnamespace.rkt")


file testevalnamespace.rkt :

(module testevalnamespace racket

	(provide foo ankh ns)
	
	(define-namespace-anchor ankh)
	(define ns (namespace-anchor->namespace ankh))
	(include "testeval.rkt")

)

file testeval.rkt :

(define (foo)
  (eval 'x ns))

if i run code from first file and do some basic stuff at toplevel using foo function:

Welcome to DrRacket, version 8.7 [cs].
Language: racket [custom]; memory limit: 8192 MB.
> (define x 7)
> (foo)
x: undefined;
 cannot reference an identifier before its definition
> ns
#<namespace:"/Users/mattei/Library/CloudStorage/Dropbox/git/library-FunctProg/testevalnamespace.rkt">
> ankh
#<namespace-anchor>
> 

i want to be able to evaluate 'x in foo procedure.

it works if i use code like this:

#lang racket

(define-namespace-anchor ankh)
(define ns (namespace-anchor->namespace ankh))


(provide foo ankh ns)

(define (foo)
  (eval 'x ns))
Welcome to DrRacket, version 8.7 [cs].
Language: racket [custom]; memory limit: 8192 MB.
> (define x 7)
> (foo)
7
> 

but i want my code packaged with modules.

Damien

Since eval uses the namespace to lookup top level variables,
you need to use the same namespace in foo as you do where you define x.

In the repl, you can get the current name space with (current-namespace).

Depending on your use case, you can either set the namespace in the repl to the one used in testevalnamespace or you can do the reverse.

i already try to change the namespace with set! but i got an error saying it is not mutable.

I suppose it exist perheaps a solution with namespace-attach-module and namespace-require but i can not find it.

for now the only solution i found is first to define a namesapce and then 'require the Scheme+ and after overload the environment by 'include-ing the the infix evaluator that bring the precedence operator:

(provide (all-defined-out)) ;; export all bindings

(define-namespace-anchor ankh)
(define ns (namespace-anchor->namespace ankh))


(require "../Scheme-PLUS-for-Racket/main/Scheme-PLUS-for-Racket/Scheme+.rkt")

(include "../Scheme-PLUS-for-Racket/main/Scheme-PLUS-for-Racket/included-files/scheme-infix.rkt")

(require "racket/logiki+.rkt")

(display "start-... : ns =") (display ns) (newline)

{x <+ 7}

(display "start-... : x =") (display x) (newline)

(eval 'x ns)

{x <- 5 + 4}

this way Scheme+ ,infix evaluator with precedence operator, module and top-level can access to the same environment:

Welcome to DrRacket, version 8.7 [cs].
Language: reader "racket/SRFI-105.rkt" [custom]; memory limit: 8192 MB.
'()
start-... : ns =#<namespace:"/Users/mattei/Dropbox/git/library-FunctProg/start-λογικι-racket+.scm">
7
start-... : x =7
7
!* : terms = (x <- 5 + 4)
!* : operator-groups = ((**) (* /) (+ -) (< > = <> ≠ <= >=) (and) (or) (<-) (<+))
!** : terms = (x <- 5 + 4)
!** : operators = (**)
!** : stack = ()
!** : odd? = #f
!** : terms = (<- 5 + 4)
!** : operators = (**)
!** : stack = (x)
!** : odd? = #t
!** : terms = (5 + 4)
!** : operators = (**)
!** : stack = (<- x)
!** : odd? = #f
operators=(**)
op=<-
mres=#f

!** : terms = (+ 4)
!** : operators = (**)
!** : stack = (5 <- x)
!** : odd? = #t
operators=(**)
op=5
mres=#f

!** : terms = (4)
!** : operators = (**)
!** : stack = (+ 5 <- x)
!** : odd? = #f
operators=(**)
op=+
mres=#f

!** : terms = ()
!** : operators = (**)
!** : stack = (4 + 5 <- x)
!** : odd? = #t
!* : terms = (4 + 5 <- x)
!* : operator-groups = ((* /) (+ -) (< > = <> ≠ <= >=) (and) (or) (<-) (<+))
!** : terms = (4 + 5 <- x)
!** : operators = (* /)
!** : stack = ()
!** : odd? = #t
!** : terms = (+ 5 <- x)
!** : operators = (* /)
!** : stack = (4)
!** : odd? = #f
!** : terms = (5 <- x)
!** : operators = (* /)
!** : stack = (+ 4)
!** : odd? = #t
operators=(* /)
op=+
mres=#f

!** : terms = (<- x)
!** : operators = (* /)
!** : stack = (5 + 4)
!** : odd? = #f
operators=(* /)
op=5
mres=#f

!** : terms = (x)
!** : operators = (* /)
!** : stack = (<- 5 + 4)
!** : odd? = #t
operators=(* /)
op=<-
mres=#f

!** : terms = ()
!** : operators = (* /)
!** : stack = (x <- 5 + 4)
!** : odd? = #f
!* : terms = (x <- 5 + 4)
!* : operator-groups = ((+ -) (< > = <> ≠ <= >=) (and) (or) (<-) (<+))
!** : terms = (x <- 5 + 4)
!** : operators = (+ -)
!** : stack = ()
!** : odd? = #f
!** : terms = (<- 5 + 4)
!** : operators = (+ -)
!** : stack = (x)
!** : odd? = #t
!** : terms = (5 + 4)
!** : operators = (+ -)
!** : stack = (<- x)
!** : odd? = #f
operators=(+ -)
op=<-
mres=#f

!** : terms = (+ 4)
!** : operators = (+ -)
!** : stack = (5 <- x)
!** : odd? = #t
operators=(+ -)
op=5
mres=#f

!** : terms = (4)
!** : operators = (+ -)
!** : stack = (+ 5 <- x)
!** : odd? = #f
operators=(+ -)
op=+
mres=(+ -)

op=+
calc : op = +
calc : a = 4
calc : b = 5
calc : odd? = #f
!** : terms = ()
!** : operators = (+ -)
!** : stack = (9 <- x)
!** : odd? = #t
!* : terms = (9 <- x)
!* : operator-groups = ((< > = <> ≠ <= >=) (and) (or) (<-) (<+))
!** : terms = (9 <- x)
!** : operators = (< > = <> ≠ <= >=)
!** : stack = ()
!** : odd? = #t
!** : terms = (<- x)
!** : operators = (< > = <> ≠ <= >=)
!** : stack = (9)
!** : odd? = #f
!** : terms = (x)
!** : operators = (< > = <> ≠ <= >=)
!** : stack = (<- 9)
!** : odd? = #t
operators=(< > = <> ≠ <= >=)
op=<-
mres=#f

!** : terms = ()
!** : operators = (< > = <> ≠ <= >=)
!** : stack = (x <- 9)
!** : odd? = #f
!* : terms = (x <- 9)
!* : operator-groups = ((and) (or) (<-) (<+))
!** : terms = (x <- 9)
!** : operators = (and)
!** : stack = ()
!** : odd? = #f
!** : terms = (<- 9)
!** : operators = (and)
!** : stack = (x)
!** : odd? = #t
!** : terms = (9)
!** : operators = (and)
!** : stack = (<- x)
!** : odd? = #f
operators=(and)
op=<-
mres=#f

!** : terms = ()
!** : operators = (and)
!** : stack = (9 <- x)
!** : odd? = #t
!* : terms = (9 <- x)
!* : operator-groups = ((or) (<-) (<+))
!** : terms = (9 <- x)
!** : operators = (or)
!** : stack = ()
!** : odd? = #t
!** : terms = (<- x)
!** : operators = (or)
!** : stack = (9)
!** : odd? = #f
!** : terms = (x)
!** : operators = (or)
!** : stack = (<- 9)
!** : odd? = #t
operators=(or)
op=<-
mres=#f

!** : terms = ()
!** : operators = (or)
!** : stack = (x <- 9)
!** : odd? = #f
!* : terms = (x <- 9)
!* : operator-groups = ((<-) (<+))
!** : terms = (x <- 9)
!** : operators = (<-)
!** : stack = ()
!** : odd? = #f
!** : terms = (<- 9)
!** : operators = (<-)
!** : stack = (x)
!** : odd? = #t
!** : terms = (9)
!** : operators = (<-)
!** : stack = (<- x)
!** : odd? = #f
operators=(<-)
op=<-
mres=(<-)

op=<-
calc : op = <-
calc : a = 9
calc : b = x
calc : odd? = #f
calc : ns = #<namespace:"/Users/mattei/Dropbox/git/library-FunctProg/start-λογικι-racket+.scm">
calc : val-a = 9
calc : val-b = 7
!** : terms = ()
!** : operators = (<-)
!** : stack = (9)
!** : odd? = #t
!* : terms = (9)
!* : operator-groups = ((<+))
9
> 

Since you export the namespace in the variable ns you can set the current namespace to it in the repl.

Running "maintesteval.rkt":

> (define x 7)
> (foo)
; x: undefined;
;  cannot reference an identifier before its definition
;   in module: ...

> (current-namespace ns)
> (define x 7)
 (foo)
7
1 Like

yes possibly.
i will test that later , because my code version is changing as i find a big caveat that is something as simple as:

{x <- 5 + 4}

give the good result 9 but never change x because it should expand at some point as (set! x 9)
but unfortunately as all my expression are quoted, and as set! MUST have an identifier as first argument and it does not exist a way in scheme to write something as (set! (eval a ns) 9) with a being 'x but anyway i 'm getting a bad syntax error in set! that require an identifier not an expression as (eval a ns) so i'm in a serious trouble and i need to deal with <- at a macro level not a procedural one with all the limitation of macros too.... long is the path :wink:

note: understand that in SRFI 105 and Scheme+ :
{x <- {5 + 4}}

works but:

{x <- 5 + 4}

in srfi 105 expand in:

($nfx$ x <- 5 + 4)

If you only need top level variables, you can use namespace-set-variable-value!.

use of REPL and its top level variable is an option,
if code works only in mofule or file that could be enought,
there will be always a few thing not working in REPL in Scheme

i can not find :

Welcome to DrRacket, version 8.6 [cs].
Language: R5RS; memory limit: 14000 MB.
> namespace-set-variable-value!
. . namespace-set-variable-value!: undefined;
 cannot reference an identifier before its definition code here

interesting, this solution works but only in the REPL, if i put my code in the maintesteval.rkt it fails again:

#lang racket

(provide foo ankh ns)

(require "testevalnamespace.rkt")

(current-namespace ns)

(define x 7)

(foo)

Welcome to DrRacket, version 8.6 [cs].
Language: racket, with debugging; memory limit: 14000 MB.
. . x: undefined;
 cannot reference an identifier before its definition
> 

In REPL when you do (current-namespace ns) you are switching to the namespace that compiles the module testevalnamespace. Then running (define x ...) in REPL defines a new binding x in ns. In maintesteval.rkt, the code (define x ...) is just an ordinary module-level definition in the module maintesteval.rkt so it has nothing to do with things in ns. To solve the problem, either eval define dynamically like top-level or use the right namespace.

Option 1.

;; in testeval.rkt
(define (foo)
  (eval 'x (current-namespace))) ;; or just drop the namespace argument

;; in maintesteval.rkt
#lang racket

(require "testevalnamespace.rkt")

(define-namespace-anchor ns-anchor-of-main)

(define x 7)

(current-namespace (namespace-anchor->namespace ns-anchor-of-main))
(foo)

Option 2. Tell Racket that you are running in top-level.

;; testeval.rkt
(define (foo)
  (eval 'x ns))

;; In maintesteval.rkt
;; racket/load is the 'top-level' language
#lang racket/load

(require "testevalnamespace.rkt")

(current-namespace ns)

(define x 7)

(println (foo))

Option 3, which is like option 2 but more explicit

;; in maintesteval.rkt
#lang racket

(require "testevalnamespace.rkt")

(current-namespace ns)

(eval '(define x 7) ns)

(foo)

Racket modules are not running like REPL. Modules define a closed set of bindings with support for separate compilation -- they are one level below the top-level, and in contrast eval are runtime-reflections.

I'd suggest avoid REPL & eval entirely and work only with modules and module-level definitions. It is also possible to work exclusively in REPL by using the racket/load language for all files. OTOH, I think the best solution is to avoid quoting everything because in general you won't know which namespace to use and the variables are not always defined at module-level; for example they could be let-bound. It should be possible to call procedural code in the macros.

1 Like

thank you,i only test the first solution and it solve the problem.I looked all solution and it seems the better.
I will provide the infix evaluator with operator precedence like that in Scheme+ for Racket.
i did not use hash table code works like that already (see below)

;;#lang reader "SRFI-105.rkt"
;;#lang r5rs

;; infix evaluator with operator precedence

;;(provide (all-defined-out)) ;; export all bindings

;; as $nfx$ will be part of the definition of Scheme+ it is not wise to use it for implementing itself !
;; at some point this would cause infinite recursive load 
;;(require "../../Scheme-PLUS-for-Racket/main/Scheme-PLUS-for-Racket/Scheme+.rkt")


;; > {5 * 3 + 2}
;; 17

;; { #f or #f and (begin (display "BAD") (newline) #t)}
;; #f 

;; > { #t and #f and (begin (display "BAD") (newline) #t)}
;; #f



;; can you believe they made && and || special forms??? yes :-) but with advantage of being short-circuited,but i admit it has been a headlock for an infix solution 
;; note: difference between bitwise and logic operator
;; (define (&& a b) (and a b))
;; (define (|| a b) (or a b))


; a list of lists of operators. lists are evaluated in order, so this also
; determines operator precedence
(define infix-operators
  (list
   ;;(list modulo quotient remainder gcd lcm)
   (list '**)
   (list '* '/)
   (list '+ '-)
   
    ; now this is interesting: because scheme is dynamically typed, we aren't
    ; limited to any one type of function
   
   (list '< '> '= '<> '≠ '<= '>=)
   ;;(list &&)
   ;;(list and) ;; does not work because of special form!
   (list 'and)
   ;;(list || ^^)
   ;;(list or)  ;; does not work because of special form!
   (list 'or)
   )
  )


;; > (define x 3)
;; > (define y -5)
;; > (! 3 * x + (* 5 y) - 7)
;; -23

;;  (define x 3)
;; > (! x * 5 >= 10)
;; #t
;; ($nfx x * 5 >= 10)
;; #t
;; ($nfx$ 3 * x + (* 5 y) - 7)
;; -23

;; > (! #f && (begin (display "BAD") (newline) #t))
;; BAD
;; #f
;;; evaluates `terms` as a basic infix expression
(define (! . terms)
  (if (null? terms) ;; i added this null case but with correct input this should not be necessary
      terms
      (car (!* terms infix-operators #f))))


;; > (define b #f)
;; > ($nfx$ #t and b)
;; #f

;; > ($nfx$ #f and (begin (display "BAD") (newline) #t))
;; #f
;;  { 4 + 3 * 2 - 19 < 0 - 4}
;; #t
(define-syntax $nfx$
  (syntax-rules ()

    ((_ ident opspecial term1 op term2) (cond ((or (equal? (quote opspecial) (quote <-)) (equal? (quote opspecial) (quote ←))) (opspecial ident (op term1 term2))) ;; {ident <- {term1 op term2}}
					      ((or (equal? (quote op) (quote ->)) (equal? (quote op) (quote →))) (op term2 (opspecial ident term1))) ;; Warning: argument names of macro do not reprensent the values contained in this case
					      (else (! (quote ident) (quote opspecial) (quote term1) (quote op) (quote term2)))))
						   
    ((_ ident opspecial term1 op term2 ...) (if (or (equal? (quote opspecial) (quote <-)) (equal? (quote opspecial) (quote ←)))
						;; there is no 'cond here because there is no way to deal with the 2nd case of 'cond above with multiple values unfortunately
						(opspecial ident ($nfx$ term1 op term2 ...)) 
						(! (quote ident) (quote opspecial) (quote term1) (quote op) (quote term2) ...))))) ;; this is in fact a general case ($nfx$ term0 ops term1 op term2 ...)

    ;; now quoting all the macros,function, symbols ... so we are no more annoyed with macro 'bad syntax' error and also this should (?) keep the 'and and 'or short-circuited functionalities.



;; DEPRECATED (2 procedures below)
;;  (andy (#t #t #t))
;; #t
;; test if short circuited:
;;  (andy (#f (begin (display "BAD") (newline) #t)))
;; #f
(define-syntax andy ;; Warhol :-)
  (syntax-rules ()
    
    ((_ (term ...)) (and (eval term (current-namespace)) ...)))) ;; as 'and and 'or has been quoted previously but as macro can not be evaluated we need procedures like the macro



(define-syntax ory ;; Oryx ? :-) ,no just call 'or on terms

   (syntax-rules ()
    
    ((_ (term ...)) (or (eval term (current-namespace)) ...)))) ;; as 'and and 'or has been quoted previously but as macro can not be evaluated we need procedures like the macro
  
  
			   

(define-syntax andy2
  (syntax-rules ()
    
    ((_ term1 term2) (if odd?
			   (and (eval term1 (current-namespace)) (eval term2 (current-namespace)))
			   (and (eval term2 (current-namespace)) (eval term1 (current-namespace)))))))


;; > (define b #t)
;; > {#f or #f or b}
;; #t
(define-syntax ory2

  (syntax-rules ()
    
    ((_ term1 term2) (if odd?
			   (or (eval term1 (current-namespace)) (eval term2 (current-namespace)))
			   (or (eval term2 (current-namespace)) (eval term1 (current-namespace)))))))




;; evaluate one group of operators in the list of terms
(define (!** terms stack operators odd?)


  (display "!** : terms = ") (display terms) (newline)
  (display "!** : operators = ") (display operators) (newline)
  (display "!** : stack = ") (display stack) (newline)
  (display "!** : odd? = ") (display odd?) (newline)

					; why `odd?`? because scheme's list-iteration is forwards-only and
					; list-construction is prepend-only, every other group of operators is
					; actually evaluated backwards which, for operators like / and -, can be a
					; big deal! therefore, we keep this flipped `odd?` counter to track if we
					; should flip our arguments or not


  ;; sometimes quoted args must be evaluated, depending of odd? args order must be swaped,sometimes both !
  (define (calc-proc op a b) ;; keep in mind that now the op-erator and args are quoted !
 
    (define proc (eval op (current-namespace)))  ;; this only works with procedure, not special form !
    ;;(display "before eval arg")
    (define val-a (eval a (current-namespace)))
    (define val-b (eval b (current-namespace)))
    ;;(display "after eval arg")
    (if odd? (proc val-a val-b) (proc val-b val-a)))

  
  (define (calc op a b) ;; keep in mind that now the op-erator and args are quoted !
    (display "calc : op = ") (display op) (newline)
    (display "calc : a = ") (display a) (newline)
    (display "calc : b = ") (display b) (newline)
    (display "calc : odd? = ") (display odd?) (newline)
    
    ;; special forms cases else procedure
    (cond ((eq? op 'and) (andy2 a b))
	  ((eq? op 'or) (ory2 a b))
	  (else (calc-proc op a b)))) ;; procedure case



  
  (cond ((null? terms) stack) ; base case
	;; operator we can evaluate -- pop operator and operand, then recurse
	((and (> (length stack) 1) (begin
				     (display "operators=") (display operators) (newline)
				     (let* ((op (car stack))
				   	    (mres (memq op operators)))
				       (display "op=") (display op) (newline)
				       (display "mres=") (display mres) (newline) (newline)
				       mres)))
	      ;;(memq (car stack) operators))
	      
	 (let ((op (car stack))
	       (fst (car terms))
	       (snd (cadr stack)))
	   (display "op=") (display op) (newline)
	   (!** (cdr terms)
		(cons (calc op fst snd) (cddr stack))
		operators
		(not odd?))))
	
	;; otherwise just keep building the stack
	(else (!** (cdr terms)
		   (cons (car terms) stack)
		   operators
		   (not odd?)))))



;; evaluate a list of groups of operators in the list of terms
(define (!* terms operator-groups odd?)
  (display "!* : terms = ") (display terms) (newline)
  (display "!* : operator-groups = ") (display operator-groups) (newline)
  (if (or (null? operator-groups) ; done evaluating all operators
	  (null? (cdr terms)))    ; only one term left
      terms ; finished processing operator groups
      ;; evaluate another group -- separating operators into groups allows
      ;; operator precedence
      (!* (!** terms '() (car operator-groups) odd?)
	  (cdr operator-groups)
	  (not odd?))))




;; ; also works for inequalities!

;; { 4 + 3 * 2 - 19 < 0 - 4}

;; { #f and (begin (display "BAD") (newline) #t)}


examples:

> {5 * 3 + 2}
 17

 { #f or #f and (begin (display "BAD") (newline) #t)}
 #f 

 > { #t and #f and (begin (display "BAD") (newline) #t)}
 #f

{ 4 + 3 * 2 - 19 < 0 - 4}
#t

> x
11
> {x <- x + 1}
12
> x
12

in fact all this works in the repl but not in a function,
so my question is how to evaluate a variable ,i'm searching the equivalent for Racket of the Guile (interaction-environment) , if it exist?