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