too bad... i'm writing an infix evaluator with precedence and i need to use the already defined variable at any level,for example in a function or a macro.
Use syntax objects (syntax->list and #‵(...)) and keep the identifiers so the scopes are intact. To see if two identifiers are "the same", like comparing +, *, etc., use free-identifier=?.
Just pattern-based macros that recognize outermost operators should work too like this example. Afterwards, replace printf-reverse by calls to some infix-to-postfix conversion algorithm and use the op struct to identify operators.
#lang racket/base
(struct op (sym) #:transparent)
(define-syntax mark-$-ops
(syntax-rules (+ - * /)
[(_ () (e-acc ...))
(list e-acc ...)]
[(_ (+ e ...) expr-acc) (mark-$-ops (e ...) ((op '+) . expr-acc))]
[(_ (- e ...) expr-acc) (mark-$-ops (e ...) ((op '-) . expr-acc))]
[(_ (* e ...) expr-acc) (mark-$-ops (e ...) ((op '*) . expr-acc))]
[(_ (/ e ...) expr-acc) (mark-$-ops (e ...) ((op '/) . expr-acc))]
[(_ (expr0 e ...) expr-acc) (mark-$-ops (e ...) (expr0 . expr-acc))]))
(define-syntax $
(syntax-rules ()
[(_ e ...)
(printf "TODO: parse and convert to postfix\n~a\n"
(reverse (mark-$-ops (e ...) ())))]))
(define y 456)
(define (compute x)
(let ([z 7])
($ x + 3 * y + z / 2)))
(compute 9)
Here is the result of macro expansion displayed in the macro stepper:
yes pattern based is a way i think ,i suppose it can solve the overloaded operator problem ,but notice that when dealing operator one by one in the pattern , a user can have defined a new operator not in the pattern cases ,but perheaps i did not well understood your code if expr0 deal with specific user defined operator...
note about overload operator problem: it is the fact that when you want to compare the operator to find precedence rules you must compare quoted operators or symbols ,if you use procedure comparaison the <procedure +> could be different from <new procedure + overloaded> a way i find to solve the operator overloaded problem is quote all operators and evaluate them later (works in Guile) or rebuild a precedence list of operator each time i call the infix with precedence evaluation. Then in the precedence list :
(define infix-operators
(list
(list expt **)
(list * / %)
(list + -)
(list << >>)
(list & ∣ )
(list < > = <> ≠ <= >=)
;;(list 'dummy) ;; can keep the good order in case of non left-right assocciative operators.(odd? reverse them)
)
)
the operators are up to date with the last definitions known. (note that in the previous list operators are NOT quoted)
and this solution is only working if i have my scheme-infix.rkt module included , it is not working if required in a module because the data are then encapsulated in the module and again i have to test that in real code,not only in simple examples sometimes only made at REPL, anyway a good solution seems to make all the overload before the scheme-infix.rkt is read,so the code included (not required) know all the procedures bind to operators symbols.
The code as written only recognizes the bindings of +, -, * and / at the outermost level. Of course, if you don't want to recognize operators by bindings, it is possible to compare operators by symbols.
However, The name of the set of operators that $ recognizes could be configurable at expansion time or in user-provided code, but must be fixed before the code starts running and especially must be determined before any uses of the $ macro. At runtime, of course, you can provide a different interpretation of the names. A possible way is to have the configuration written in a separate module.
Unless you are using the top level i.e. the REPL, Racket won't let you redefine bindings. Note that the expansion time and the run time are separated, so it is important to add new operators to both expansion and run time. The macro add-new-operator implements one possible idea:
the error is caused by the overload, after that + is unknow!!!??? i do not understand (again works with guile and the same macros)
Welcome to DrRacket, version 8.7 [cs].
Language: racket, with debugging; memory limit: 8192 MB.
before plus
. . +: undefined;
cannot reference an identifier before its definition
note: i admit i have warning in guile i never have: " warning: non-idempotent binding for +'. When first loaded, value for +` comes from imported binding, but later module-local definition overrides it; any module reload would capture module-local binding rather than import." I suppose Racket is more strict.
At run time, the expressions are evaluated from top to bottom and from left to right. However, the bindings are determined at expansion time and have nothing to do with run time.
For modules, the bindings are mutually recursive. This is what the code looks like after expansion (check the macro stepper):
Because module-level bindings are mutually recursive, the + in line 4 refers to the + define at the end of the code. Therefore, at run time line 4 of the code tries to use the value of + that has not been evaluated yet, leading to the error you see. This is the same class of runtime errors as this piece of code:
#lang racket
(+ x y) ;; <- x and y has not been evaluated yet
(define x 5)
(define y 8)
yes i had noticed about the top to bottom evaluation and moved the code to the good place (seems i had not this problem in Guile?) and try the #lang racket/load it works but i cannot use it with my #lang reader "SRFI-105.rkt"
if i put #lang racket/load replacing #lang racket it does not work with the srfi 105 code reader and parser.
i got this error:
Welcome to DrRacket, version 8.7 [cs].
Language: reader "SRFI-105.rkt", with debugging; memory limit: 8192 MB.
. . ../../../../../../../../Applications/Racket v8.7/collects/compiler/private/cm-minimal.rkt:741:23: standard-module-name-resolver: collection not found
for module path: racket/lang/lang/reader
collection: "racket/lang/lang"
in collection directories:
/Users/mattei/Library/Racket/8.7/collects
/Applications/Racket v8.7/collects/
... [170 additional linked and package directories]
no package suggestions are available .
Interactions disabled.
my SRFI-105.rkt begin like this:
#lang racket/lang ;; use to be racket
(compile-enforce-module-constants #f)
(require syntax/strip-context)
(provide (rename-out [literal-read read]
[literal-read-syntax read-syntax]))
(define (literal-read in)
(syntax->datum
(literal-read-syntax #f in)))
(define (literal-read-syntax src in)
(define lst-code (process-input-code-tail-rec in))
(strip-context `(module anything racket ,@lst-code)))
;; read all the expression of program
...
yes it worked but now the 'require' is forbidden and with SRFI-105 this is a problem because the reader infix does not include and parse recursively the files, for this reason i used require with a #lang reader "SRFI-105.rkt", this is hard to solve.
I think it would be nice to take a step back and think about what you really want to do. Who will be the users of this library? How will the library be used? Do you intend that regular Racket programs are able to require your library, or is it in its own ecosystem entirely?
From a quick glance, it looks like you are circumventing the module system and hygienic macro system, and using reflection liberally. Those are things that regular Racket programs would not do, unless there is a really good justification. I wouldn’t be surprised if right now Racket programs can’t interop well with the library.