How to define a function in scm scheme that tests if its parameter is a macro? - scheme

For example, assuming 'match is a macro and 'car isn't:
> (macro? 'match)
#t
> (macro? 'car)
#f

Most schemes have no such macro? function. To distinguish normal functions from macros you can use procedure? from RnRS:
> (procedure? car)
#t

The problem is that you cannot name the keyword using Scheme syntax:
> (procedure? let)
Exception: invalid syntax let
So you have to use a symbol, like 'let, to refer to it. Given that eval needs to be able to tell keywords apart from other identifiers, you can try something like this:
(define keyword?
(lambda (symbol)
(guard (x [else (syntax-violation? x)])
(eval symbol)
#f)))
(keyword? 'let) ⇒ #t
(keyword? 'car) ⇒ #f
(keyword? 'does-not-exist) ⇒ #f
But this is certainly a rather big hammer. And this single-argument form of eval is a Chez Scheme extension, supplying (interaction-environment) as the default environment. It is also not completely safe because this hangs:
(let-syntax ([foo (lambda (x) (raise "oops"))])
(keyword? 'foo))

Related

Standard way to handle quoted symbol in lisp macros in Scheme

For some code I was working I've needed to handle 'x inside macro. What is standard way of handling those values?
I have code like this:
(define (quoted-symbol? x)
(and (pair? x) (eq? (car x) 'quote) (symbol? (cadr x)) (null? (cddr x))))
(define-macro (test x)
(if (quoted-symbol? x)
`(begin
(display ',(cadr x))
(newline))))
(test 'hello) ;; 'hello will be expanded into list (quote hello)
Is this how this should be handled, or is just in macro you don't use quoted symbols?
NOTE: I'm not asking about hygienic macros (I'm asking about real lisp macros), so please no answers with hygienic macros.
EDIT:
My macro works correctly in Guile and BiwaScheme and in my own scheme like lisp in JavaScript. Here is better example:
(define-macro (test x)
(if (quoted-symbol? x)
`',(cadr x)))
(define (example arg)
(list arg (test 'world)))
(example 'hello)
the question was not about display, but about (cadr x).
EDIT2: You've asked so here you go, my macro:
(define-macro (--> expr . code)
"Helper macro that simplify calling methods on objects. It work with chaining
usage: (--> ($ \"body\")
(css \"color\" \"red\")
(on \"click\" (lambda () (print \"click\"))))
(--> document (querySelectorAll \"div\"))
(--> (fetch \"https://jcubic.pl\") (text) (match /<title>([^<]+)<\/title>/) 1)
(--> document (querySelectorAll \".cmd-prompt\") 0 \"innerText\")"
(let ((obj (gensym)))
`(let* ((,obj ,(if (and (symbol? expr) (not (null? (match /\./ (symbol->string expr)))))
`(.. ,expr)
`,expr)))
,#(map (lambda (code)
(let ((name (gensym))
(value (gensym)))
`(let* ((,name ,(cond ((quoted-symbol? code) (symbol->string (cadr code)))
((pair? code) (symbol->string (car code)))
(true code)))
(,value (. ,obj ,name)))
,(if (and (pair? code) (not (quoted-symbol? code)))
`(set! ,obj (,value ,#(cdr code)))
`(set! ,obj ,value)))))
code)
,obj)))
;; ---------------------------------------------------------------------------------------
(define (quoted-symbol? x)
"(quoted-symbol? code)
Helper function that test if value is quoted symbol. To be used in macros
that pass literal code that is transformed by parser.
usage:
(define-macro (test x)
(if (quoted-symbol? x)
`',(cadr x)))
(list 'hello (test 'world))"
(and (pair? x) (eq? (car x) 'quote) (symbol? (cadr x)) (null? (cddr x))))
the macro is used in my scheme like lisp in JavaScript, like the doc string suggest:
(--> document (querySelectorAll ".class") 0 "innerText")
I want to support:
(--> document (querySelectorAll ".class") 0 'innerText)
The code can be tested online at: https://jcubic.github.io/lips/ (You need to copy/paste the code since current version allow only method calls).
To get expansion you can use
(pprint (macroexpand (--> document (querySelector "x"))))
if it don't work (don't expand) it mean that macro is broken somehow.
dot is build in function that get property of an object and .. macro:
(define-macro (.. expr)
"(.. foo.bar.baz)
Macro that gets value from nested object where argument is comma separated symbol"
(if (not (symbol? expr))
expr
(let ((parts (split "." (symbol->string expr))))
(if (single parts)
expr
`(. ,(string->symbol (car parts)) ,#(cdr parts))))))
that can be use to get nested property like (.. document.body.innerHTML)
Scheme doesn't have "real lisp macros". Some implementations has something similar, but the forms have different names and uses. They are not portable at all.
The standard way of handling 'x is to handle it like an expression that gets evaluated in the expansion. Eg.
(define var 'x)
(test 'x)
(test var)
The two test forms should amount to the same even though the macro test gets (quote x) in the first and the symbol var in the second. At the time of the expansion var does not exist since the implementation can expand all the macros before starting.
You implementation of test will not work. Eg. the display might be run one or twice and then each time you call a procedure that uses it it will gfail since the expansion is the undefined value and it might not be fit for evaluation. eg.
(define (example arg)
(list arg (test 'w)))
When this is defined you get 'w or (quote w) printed with a newline and then the procedure it tries to store is:
(define (example arg)
(list arg #<undefined>))
Note that what constitutes the undefined value is chosen by the implementaion, but I know for sure that in many implementaions you cannot evaluate #<undefined>.

Just eval first symbol (CHICKEN Scheme)

How can I evaluate an s-expression only by the first term?
(define (fn x y) (print x) (print y))
(eval '(fn a b))
I am trying to evaluate something like this on a bigger expression but the interpreter is complaining that a and b variables don't exist (unbound variable a).
Is there something I can do to leave symbols as they are?
I have been trying to find information about this but I can't find it anywhere.
How about the following?
(let ((expr '(fn a b)))
(cons (eval (car expr)) (cdr expr)))
But please note that if you have to rely on eval, you're almost certainly doing things wrong.

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.

Testing for the definedness of a variable in Scheme

Besides regular definitions like (define variable value) Scheme also allows for uninitialized definitions like (define variable), when the variable is bound to some value later on with the aid of set!.
Are there procedures allowing to test whether a symbol is a defined (not necessarily initialized) variable? Something like (defined? 'variable) which should return #t if variable is defined and #f otherwise?
The form (define var) is a non-standard extension.
According to R5RS define has one of the following forms:
(define <variable> <expression>)
(define (<variable> <formals>) <body>)
(define (<variable> . <formal>) <body>)
As far as I can tell the same goes for R6RS and R7RS.
Most likely (define foo) expands to (define foo the-undefined-value) in your implementation. This means you can use (if (eq? foo the-undefined-value) ...) to test whetherfoo` is has been initialized or not.
http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-8.html#%_idx_190
Update:
I checked R6RS and it says:
(define <variable> <unspecified>)
where <unspecified> is a side-effect-free expression returning
an unspecified value.
Consider
(define foo)
(define bar)
It is up to the implementor whether the same unspecified value that is bound to both foo and bar.
Try this program:
(define unspecified)
(define unspecified1)
(eq? unspecified unspecified1)
If the program evaluates to #t then you can write an initialized? predicate like this:
(define unspecified)
(define (initialized? x) (not (eq? x unspecified)))
(define test)
(initialized? test)
(set! test 42)
(initialized? test)
There is simple universal solution based on try-catch. I've tested it on Gambit v4.9.3.
(define (defined? var-symbol)
(with-exception-handler
(lambda (e) void)
(lambda () (not (eq? void (eval var-symbol))))
)
)
And here are the test cases:
> (defined? 'a)
#f
> (define a 123)
> (defined? 'a)
#t
> (defined? 'x)
#f
> (define x)
> (defined? 'x)
#t
> (defined? 'f)
#f
> (define (f a b) (+ a b))
> (defined? 'f)
#t
With this you can make conditional definitions:
(define (define-if-not var-symbol init)
(if (defined? var-symbol) void
(let ((value (init)))
(eval (list 'define var-symbol value))
value
)
)
)
The tests:
> (define a 'abc)
> (define (make-123) 123)
> (define-if-not 'a make-123)
#<procedure #2 void>
> (define-if-not 'b make-123)
123
> a
abc
> b
123
This variant of define-if-not has a caveat: if the value is a symbol, eval treats it as a reference. This is the short demo:
> (define value 123)
> (eval (list 'define 'a value))
> (define value 'abc)
> (eval (list 'define 'a value))
*** ERROR -- Unbound variable: abc
The following [nasty] solution overcomes it for Gambit:
(define define-if-not-private)
(define (define-if-not var-symbol init)
(if (defined? var-symbol) void
(let ((value (init)))
(set! define-if-not-private (lambda () value))
(eval (list 'define var-symbol '(define-if-not-private)))
value
)
)
)
According to the scheme report (standard) define is used to define a variable. (put it into existence) Using define without an expression like (define test) defines the variable to some value chosen by the implementation.
It can only be used once in the same scope for the same variable, thus set! is to alter an existing variable to something else, but it cannot remove it's existence.
There is nothing in the report to remove a binding or to check if a binding exists. Using a variable without it being defined will have undefined consquences.
Implementations may have feature beyond the report. These things are typically stuff the guts of a scheme system should know about and they may expose it to the user, but it is implementation dependent and not standard.

How do I find out if a variable is a letter in Scheme?

Simple question, simple answer for someone who actually uses scheme. How can I find out if a variable is a letter of the alphabet?
I assumed it was something like this (letter? x) where x is some indefinate type. Can anyone tell me what boolean function could be used?
edit:
How could I make something that looks like this: (somFunction-isALetter? a)
Return: #t
Where a is not a variable.
In Racket, the char-alphabetic? function only takes characters as arguments, but it's easy to define a function that returns false for all non-characters instead of failing:
(define (letter? x) (and (char? x) (char-alphabetic? x)))
Use the char-alphabetic? procedure for this. From the documentation:
char-alphabetic? returns #t if char has the Unicode “Alphabetic” property.
Use it like this:
(char-alphabetic? #\a)
> #t
If the character is in a variable:
(define x #\a)
(char-alphabetic? x)
#t
Notice that char-alphabetic? only works for characters.
UPDATE:
Re-reading the question I believe I misunderstood it. If you're interested in finding out if a variable 's name is just a single letter, this will work:
(define (is-variable-a-letter? x)
(let ((var (string->list (symbol->string x))))
(and (= (length var) 1)
(char-alphabetic? (car var)))))
(is-variable-a-letter? 'x)
> #t
On the other hand, if you're interested in the actual contents of the variable, then apply the first part of this answer.

Resources