Define a macro that returns the operator of an expression in Scheme? - scheme

I'm looking for functionality like this:
(op (+ 1 2))
; +
I can’t for the life of me seem to figure out how to do this using define-macro. Any help?
Thanks,
Edit:
It's especially confusing cause I can do:
(car '(+ 1 2))
; +
But if I do:
(define-macro (op expr)
(car expr))
(op '(+ 1 2))
It doesn't work.

OP has defined the macro op as if it were a function, but Lisp macros do not work this way. The macro form is evaluated to produce a new form which substitutes for the original macro call, yet the macro arguments are passed into the macro body unevaluated. This means that within the macro body of op, car operates not on the data (+ 1 2), but rather on the data (quote (+ 1 2)).
The goal of the macro op is not to evaluate (car expr), but to produce the form (car expr) (where expr is replaced by the value of the macro argument), which is then evaluated in the REPL after the macro expansion has taken place. One could do this either using list:
(define-macro (opl expr)
(list 'car expr))
or using quasiquotation:
(define-macro (opq expr)
`(car ,expr))
Here, the backquote introduces a template for a list, and the comma causes the symbol expr to be evaluated to its value ((quote (+ 1 2))), and the result inserted into the list. A simple quoted list, e.g. '(car expr) would evaluate to the list (car expr), where expr is just the symbol expr. With quasiquotation, ,expr evaluates to the value of the argument provided in a macro call, e.g. `(car ,expr) --> (car '(+ 1 2)). Note that (list 'car expr) produces the same form when expr is '(+ 1 2), as with (opl '(+ 1 2))
This define-macro syntax is almost identical to the traditional defmacro syntax of Common Lisp, the difference there being that with defmacro the name of the macro goes before a list of formal parameters, e.g. (defmacro op (expr) ;...). define-macro is not available in Standard Scheme, but some Scheme implementations do support it. Guile Scheme supports both defmacro and define-macro. Both of the above macro solutions work in Guile:
scheme#(guile-user)> (opl '(+ 1 2))
$2 = +
scheme#(guile-user)> (opq '(+ 1 2))
$3 = +

Related

evaluating my own functions from list with eval, R5RS

I am having problems with this
e.g. i have
(define (mypow x) (* x x))
and I need to eval expressions from given list. (I am writing a simulator and I get a sequence of commands in a list as an argument)
I have already read that R5RS standard needs to include in function eval as second arg (scheme-report-environment 5), but still I am having issues with this.
This works (with standard function):
(eval '(sqrt 5) (scheme-report-environment 5))
but this does not:
(eval '(mypow 5) (scheme-report-environment 5))
It says:
../../../../../../usr/share/racket/collects/racket/private/kw.rkt:923:25: mypow: undefined;
cannot reference undefined identifier
Eventhough simply called mypow in prompt returns:
#<procedure:mypow>
Any advice, please? (btw I need to use R5RS)
(scheme-report-environment 5) returns all the bindings that are defined in the R5RS Scheme standard and not any of the user defined ones. This is by design. You will never be able to do what you want using this as the second parameter to eval.
The report mentions (interaction-environment) which is optional. Thus you have no guarantee the implementation has it, but it will have all the bindings from (scheme-report-environment 5)
For completeness there is (null-environment 5) which only has the bindings for the syntax. eg. (eval '(lambda (v) "constan) (null-environment 5)) works, but (eval '(lambda (v) (+ 5 v)) (null-environment 5)) won't since + is not in the resulting procedures closure.
Other ways to get things done
Usually you could get away without using eval alltogether. eval should be avoided at almost all costs. The last 16 years I've used eval deliberately in production code twice.
By using a thunk instead of data:
(define todo
(lambda () ; a thunk is just a procedure that takes no arguments
(mypow 5))
(todo) ; ==> result from mypow
Now imagine you have a list of operations you'd like done instead:
(define ops
`((inc . ,(lambda (v) (+ v 1))) ; notice I'm unquoting.
(dec . ,(lambda (v) (- v 1))) ; eg. need the result of the
(square . ,(lambda (v) (* v v))))) ; evaluation
(define todo '(inc square dec))
(define with 5)
;; not standard, but often present as either fold or foldl
;; if not fetch from SRFI-1 https://srfi.schemers.org/srfi-1/srfi-1.html
(fold (lambda (e a)
((cdr (assq e ops)) a))
with
todo)
; ==> 35 ((5+1)^2)-1

Eval not working in Racket

I am using following code modified from Solving Infix Arithmatic in LISP with definition of atom from Check if an argument is a list or an atom to have an infix arithmetic solver:
(define atom? (or/c number? symbol? boolean? string?))
(define (solve expression)
(define templist '())
(println expression)
(if (atom? expression)
expression
(begin
(set! templist (list (second expression)
(solve (first expression))
(solve (third expression)) ))
(println templist)
(eval templist) ) ) )
(solve '(3 + 2))
The output is as follows:
'(3 + 2)
3
2
'(+ 3 2)
+: unbound identifier;
also, no #%app syntax transformer is bound in: +
Hence, the templist is created all right (+ 3 2) but there is error at eval level. Why is '+' seen as an 'unbound identifier'? The eval function otherwise works well on the command line in DrRacket:
> (eval '(+ 3 2))
5
Where is the problem and how can it be solved? Thanks.
Have you not been learning from the answers to your previous questions? Do not use set!, it is not good Scheme/Racket style. It’s especially egregious here because it is doing absolutely nothing at all; take it out and use let (or local, or block with internal definitions, if you’d prefer).
That aside, eval is equally evil, and you don’t need it here. Functions are first class; create a mapping between symbols and functions, then just use the mapping to fetch the relevant function to invoke.
(define (operator->procedure op)
(case op
[(+) +]
[(-) -]
[(*) *]
[(/) /]
[else (error 'operator->procedure "unknown operator ~v" op)]))
(define (solve expression)
(if (atom? expression)
expression
((operator->procedure (second expression))
(solve (first expression))
(solve (third expression)))))
To be even clearer, you could use Racket’s pattern-matching form, match:
(define (solve expression)
(match expression
[(? atom) expression]
[(list a op b)
((operator->procedure op) (solve a) (solve b))]))

Can someone explain equality to me in scheme/racket?

So I stumbled across this today and it has me puzzled.
(define (x) '(1))
(eq? (x) (x)) ;=> #t
(eq? '(1) '(1)) ;=> #f
(define (y) (list 1))
(eq? (y) (y)) ;=> #f
(eq? (list 1) (list 1)) ;=> #f
Can anyone explain what's happening here ?
When compiled this program
(define (x) '(1))
(eq? (x) (x))
(eq? '(1) '(1))
is compiled into (something like):
(define datum1 '(1))
(define datum2 '(1))
(define datum3 '(1))
(define (x) datum1)
(eq? (x) (x))
(eq? datum2 datum3)
Therefore (x) will always return the object stored in datum1.
The expressions (eq? '(1) '(1)) on the other hand will
find out that datum2 and datum3 does not store the same object.
Note: There is a choice for the compiler writer. Many Scheme implementation will compile the above program to:
(define datum1 '(1))
(define (x) datum1)
(eq? (x) (x))
(eq? datum1 datum1)
and then the result will be true in both cases.
Note: The documentation of quote doesn't explicitly state whether multiple occurrences of '(1) in a program will produce the same value or not. Therefore this behavior might change in the future. [Although I believe the current behavior is a deliberate choice]
eq? checks if the objects are the same (think "if the pointer refers to the same address in memory").
In the first case you're working with literals created at compile time. Comparing (and modifying) literals is generally undefined behaviour. Here it looks like procedure x returns the same literal every time, but in the second expression it looks like the 2 literals are not the same. As I said, undefined behaviour.
In the second case you're not working with literals but list creates a new list at execution time. So each call to y or list creates a fresh list.
uselpa's answer is correct.† I wanted to expand on what a quoted datum is, a little further, though.
As you know, all Scheme programs are internally read in as a syntax tree. In Racket, in particular, you use the read-syntax procedure to do it:
> (define stx (with-input-from-string "(foo bar)" read-syntax))
> stx
#<syntax::1 (foo bar)>
You can convert a syntax tree to a datum using syntax->datum:
> (syntax->datum stx)
'(foo bar)
quote is a special form, and what it does is return the quoted portion of the syntax tree as a datum. This is why, for many Scheme implementations, your x procedure returns the same object each time: it's returning the same portion of the syntax tree as a datum. (This is an implementation detail, and Scheme implementations are not required to have this behaviour, but it helps explain why you see what you see.)
And as uselpa's answer says, list creates a fresh list each time, if the list is non-empty. That's why the result of two separate non-empty invocations of list will always be distinct when compared with eq?.
(In Scheme, the empty list is required to be represented as a singleton object. So (eq? '() '()) is guaranteed to be true, as is (eq? (list) '()), (eq? (cdr (list 'foo)) (list)), etc.)
† I would not use the phrasing "undefined behaviour" for comparing literals because that's easily confused with the C and C++ meaning of UB, which is nasal demons, and although the result of comparing literals may not be what you expect, it would not cause your program to crash, etc. Modifying literals is nasal demons, of course.

Issues with evaluating expressions from user input

I'm trying to make a recursive definition that reads and execute user expressions, such as (3 + 5). Everything is working, except of one problem with the arithmetic symbol.
I managed to replicate the error in a simpler example:
(define v '(1 + 3))
((cadr v) 2 4)
The (cadr v) is the + symbol, but for some reason the procedure can't be executed on the two arguments that followed. Am I missing something?
I think that's because
(cadr v)
returns '+ not + (literal + not a + function).
You need to evaluate it before applying it to arguments.
This should work:
((eval (cadr v)) 2 4)
^evaluates the '+ to +
edit
This worked in racket in interactive mode.
I'm not really sure what's the difference, but made it work in r5rs mode in racket (a script):
#lang r5rs
;required by r5rs
(define user-initial-environment (scheme-report-environment 5))
(define v '(1 + 2))
;eval expects a quoted expression
;(it seems that if it's a function it has to have arguments too)
;and evaluation environment.
((eval (cadr v) user-initial-environment) 2 4)
As others have pointed out, the problem is that the list you've constructed contains the symbol plus, rather than the function plus.
At its heart, this is the same reason that '(a b) returns a list of two symbols, rather than signalling an unbound identifier error; the quote starts a term in a "data language" where legal identifiers are interpreted as symbols, rather than as variable references.
The question, of course, is what you should do about it. Some here have suggested using 'eval'; this is probably a bad idea, for reasons that I think Matthew Flatt captures elegantly in his blog post on the topic.
Instead, you should probably write a simple mapping function. Here's the way I'd write it. If you use my code in an assignment, be sure to credit me :).
#lang racket
;; a mapping from symbols to operators
(define operator-hash
(hash '+ +
'- -
'* *))
;; ... and whatever other operators you want.
;; example of using it:
(hash-ref operator-hash '+) ;; ==> +
Try this:
(define v '(1 + 3))
(let ((operator (eval (cadr v)))
(operand1 (car v))
(operand2 (caddr v)))
(apply operator (list operand1 operand2)))
You can do it this way with eval in Guile:
(define (infix-eval v)
(eval (list (cadr v)(car v)(caddr v))
(interaction-environment)))
> (infix-eval '(1 + 2))
3
Rather than using interaction-environment, you could supply another environment for evaluation, where you could also define some other symbols not found in standard Scheme, so that expressions like (7 % 3) and (2 ^ 6) would also work.

How does `let` work in Scheme?

I use let to create a temporary variable, and then use this temporary variable in the next statement. However, DrScheme complained,
let: bad syntax (not an identifier and expression for a binding) in: temp
This is my code snippet:
(define (case-one-helper str)
(let (temp (substring str (+ 3 (string-contains str "my"))))
(substring temp (string-contains temp " "))))
I wonder if the value of variable created by let has to be known at compiled time?
Edit
I've just figured out, missing ().
Thanks,
While not exactly the problem you're experiencing, but an aside based on your questioning about the sequence of evaluating the arguments, let is also "syntactic sugar" for a lambda followed by it's arguments that are first evaluated and then passed to the lambda which is then evaluated.
For instance:
(let ((a (list 1 2 3))
(b (list 4 5 6)))
(cons a b))
is the same as:
((lambda (list-a list-b) (cons list-a list-b)) (list 1 2 3) (list 4 5 6))
So, if you're ever wondering about evaluation sequence, the arguments are evaluated fully before the body is evaluated (and one argument cannot refer to an argument preceding it ... use let* for something that requires bindings like that).
You need to put another set of parentheses around your let declarations:
(define (case-one-helper str)
(let ((temp (substring str (+ 3 (string-contains str "my")))))
(substring temp (string-contains temp " "))))

Resources