Scheme: match-lambda syntax error - syntax

I am writing a function annotate that uses match-lambda often with recursive calls to annotate. Here is one of the patterns and matches:
(`(,<param> . ,<params> (lambda (,<args>) ,<stmt> . ,<stmts>))
`(CLOSURE ENV ,(append (append `(,<param>) `(,<params>))`(,<args>)) (lambda (ENV) ,(map annotate `(,<stmt> . ,<stmts>)))))
I am getting a complaint that the first use of "." is illegal -- between "param" and "params" -- but I can't figure out why. This pattern and match doesn't get any complaints and seems very similar with regards to the first ".":
(`(λ (,<param1> . ,<params>) ,<stmt> . ,<stmts>)
`(CLOSURE ENV ,(map annotate `(,<param1> . ,<params>)) (λ (ENV) ,(map annotate `(,<stmt> . ,<stmts>)))))
Any advice is appreciated.
Thanks.

The "." is used in Racket and in Scheme to represent "improper lists"; that is, sequences of cons pairs that don't end with "empty". So, for instance,
'(3 4 . 5)
is a shorthand for
(cons 3 (cons 4 5))
The 'dot' is used to mean: "I'm done with the list-like part; here's the final value, use this instead of "empty". For this reason, you can't use the dot just anywhere in the list; it has to be just before a single, final element. In your example, the dot in the pattern precedes a bunch of elements, not just one.
Looking at your example, it looks you want to use the "..." syntax here, e.g.:
(match '(a b c d e)
[`(,x ... d e) 'ok])
(Actually, you can also use dots for infix notation in Racket, but I'm pretty sure that's not what you're trying to do, here.)

Related

What happened in scheme when defining a symbol to be something else?

I'm a beginner of the Scheme language.
Recently I found that the data type symbol can be displayed using quote, like this:
> 'E
E
> (quote E)
E
However, if the code below executed, every kind of quote may fail:
> (define 'E 123)
> 'E
E: undefined;
cannot reference an identifier before its definition
> 'abc
abc: undefined;
cannot reference an identifier before its definition
So what happend when code (define 'E 123) being executed?
First you asked Scheme to evaluate (define 'E 123). Let's put a quote in front of that, to see what it looks like without the ' shorthand. You can always do this: quote any expression to ask Scheme, "What do you think this value is?"
> '(define 'E 123)
=> (define (quote E) 123)
Well, in Scheme, (define (x ...) ...) is a shorthand for (define x (lambda (...) ...)): it's just a convenient shorthand for defining a function. So in this case (define (quote E) 123) is the same as (define quote (lambda (E) 123)). Thus, the symbol you are redefining is quote, and you define it to be a function of one parameter which always returns 123.
Next you asked to evaluate 'E. Again let's expand that to look through the shorthand:
> ''E
=> (quote E)
You now call the quote function you defined, and pass it the variable E as an argument. But E has not previously been defined, so this fails. If you wanted to, you could first define E to have any value, and then perhaps 'E would return 123. It rather depends on what Scheme evaluator you are using: the one I found does not much appreciate it when you try to redefine quote, but apparently yours does not mind, so I suspect you would get 123, and that you would get the same result if you defined abc and then evaluated 'abc.
in general (define name ...) is converted in (bind name) at the beginning of the scope and in the place where define appears, it is executed (set! name ...). You need to define a symbol, not a (quote name). Because define is a special form, the rules of evaluation are particular, not general application -- define is not a function call.

miniKanren: How to define #s and #u?

In miniKanren, succeed can be defined as (define succeed (== #t #t)), and fail can be defined as (define fail (=== #t #f)). But what about #s and #u as short forms of succeed and fail, as they appear in The Reasoned Schemer?
(define #s succeed) produces an error in Racket:
Welcome to Racket v7.2.
> (require Racket-miniKanren/miniKanren/mk)
> (define #s succeed)
; readline-input:2:8: read-syntax: expected `(`, `[`, or `{` after `#s` [,bt
; for context]
#<procedure:...iniKanren/mk.rkt:337:4>
; readline-input:2:18: read-syntax: unexpected `)` [,bt for context]
I have the feeling that this has something to do with reader macros.
How can I define #s for succeed and #u for fail in Scheme and also in Racket?
I am using the canonical miniKanren implementation for Scheme and the canonical miniKanren implementation for Racket.
Identifiers in Racket can not begin with #. It is simple to bind the identifiers s and u. Redefining the meaning of #s and #u is not as simple, since it needs to happen in the reader. Normally #something signals to reader that something special is to be read.
The input (foo bar) will be read as a list, #(foo bar) will be read as a vector, and #s(foo bar) will be read as a structure. You can read about the standard syntax here:
https://docs.racket-lang.org/reference/reader.html?q=%23s#%28mod-path._reader%29
Now if you want to change the meaning of #s and #u you need to look at readtables.
Each time the reader sees an # it consults a readtable to see how to handle the following characters. Since reading happens before parsing/expansion and evaluation, you can't change the reader simply by calling a function in your program. You will need to either use
the #reader extension mechanism or create your own language.
For more on readtables: https://docs.racket-lang.org/reference/readtables.html?q=reader-macro
The Guide has an example of how to use reader extensions:
https://docs.racket-lang.org/guide/hash-reader.html
I solved all the book using
(define succeed
(lambda (s)
`(,s)))
(define SUCC succeed)
(define fail
(lambda (s)
'()))
On the other side, you should consult the source code provided by Friedman & Byrd. I solved it using mit-scheme -- no specific feature of racket is used, R6RS is enough.
For Racket, #s and #u can be defined as such (reference: Using Racket for The Reasoned Schemer):
;; #s for succeed.
(current-readtable
(make-readtable (current-readtable)
#\s
'dispatch-macro
(lambda (ch port src line col pos) succeed)))
;; #u for fail.
(current-readtable
(make-readtable (current-readtable)
#\u
'dispatch-macro
(lambda (ch port src line col pos) fail)))
Note that this only works in the REPL.
This defines #s and #u by modifying the readtable.
For Scheme, adding read syntax is defined in SRFI-10 sharp-comma external form, but the resulting #,() forms are probably awkward for most tastes. For Scheme, it is best to just define s and u because there is currently no portable way to define #s and #u.

How to use the "%bag-of" primitive inside a predicate in Racklog

This time my problem is mostly with Racklog. I guess. Could also be the Racket syntax this time.
The idea is rather simple. I have a logic-base made up of places and objects and I just wanted to try out printing all the objects using the %bag-of primitive.
My logic-base looks like this:
(define %contains
(%rel ()
[('bridge 'phaser)]
[('engine_room 'toolkit)]
[('toolkit 'screwdriver)]
[('toolkit 'tricorder)]
[('inventory '(communicator, no_tea))]
)
)
Now I have my predicate which is the following one. It should be simply called with the query "(%which () (%list_objects 'toolkit))" and then give out all the items inside the toolkit for example.
(define %list_objects
(%rel (place)
[(place)
(%which (objects)
(%let (x)
(%bag-of x (%contains place x)
objects)))]
)
)
The weird thing is when I just thake the part from the "%which (objects)...)" onwards and throw it directly into the listener, it works perfectly fine. But if I'm using it inside the predicate, it throws this exception:
"application: not a procedure;
expected a procedure that can be applied to arguments
given: '((objects screwdriver tricorder))
arguments...: [none]"
I tried rearranging the code several times, but right now I'm quite stumped about what I did wrong. I would appreciate a little hint what I as a total newbee to Scheme and Racket missed out here. My thanks in advance!
The problem is that the goal (%which ...) returns an answer (not a new relation). Therefore %list_objects can't be used in the way you want.
Maybe this works for you?
#lang racket
(require racklog)
(define %contains
(%rel ()
[('bridge 'phaser)]
[('engine_room 'toolkit)]
[('toolkit 'screwdriver)]
[('toolkit 'tricorder)]
[('inventory '(communicator, no_tea))]))
(define %list_objects
(%rel (place)
[(place)
(%let (x) (%contains place x))]))
(%which (x) (%list_objects x))
(%more)
(%which (bag) (%let (x) (%bag-of x (%list_objects x) bag)))
(define tools-in-toolkit (map cdar (%find-all (tool) (%contains 'toolkit tool))))
(define %in-toolkit
(%rel (tool)
[(tool) (%member tool tools-in-toolkit)]))
(%find-all (tool) (%in-toolkit tool))
Output:
'((x . bridge))
'((x . engine_room))
'((bag bridge engine_room toolkit toolkit inventory))
'(((tool . screwdriver)) ((tool . tricorder)))

How to make a "define" that accepts string in the first parameter in SISC Scheme?

Let's call this function "dynamic-define".
Basically I want to write a macro or lambda that works like this:
$ (dynamic-define "variable" 123)
$ variable
$ => 123
I tried it:
(define-syntax dynamic-define
(syntax-rules ()
((_ string <body>)
(eval `(define ,(string->symbol string) <body>)))))
and it works as expected but doesn't seem to be a good solution.
I tried to use without eval like this:
(define-syntax dynamic-define
(syntax-rules ()
((_ string <body>)
(define (string->symbol string) <body>))))
But when I try to use I get this error:
Error: invalid syntax (define (string->symbol "variable") 123)
What should I do?
(PLEASE: edit this question to fit native English and erase this line please)
You're running against a fundamental problem: you cannot do a real dynamic define in a "clean" way, hence your attempt using eval. Note that the two solutions above are both not dynamic -- all they give you is the ability to write "foo" instead of foo. As I said elsewhere, using eval is usually bad, and in this case it's worse since it's eval that is used from a macro which makes it very weird. This is in addition to having an implicit quasi-quote in your macro that makes things even more confusing. You could just as well define the whole thing as a plain function:
(define (dynamic-define string <body>)
(eval `(define ,(string->symbol string) ,<body>)))
If you really need this to work, then it's best to take a step back and think about what it is that you need, exactly. On one hand, the above solutions are not dynamic since they require using the macro with a string syntax
(dynamic-define "foo" 123) ; instead of (define foo 123)
but how would it look to have a real dynamic definition that takes in a string? You'd probably expect this to define b:
(define a "b")
(dynamic-define a 123)
but this only becomes more confusing when you consider how it interacts with other bindings. For example:
(define y 123)
(define (foo s)
(define x 456)
(dynamic-define s 789)
(+ x y))
Now, assuming that dynamic-define does what you want it to do, think about what you'd get with (foo "x") and (foo "y"). Worse, consider (foo "s") and (foo "+"). And even worse, what about
(foo (random-element '("x" "y" "s" "+" "define")))
? Clearly, if this dynamic-define really does some dynamic definition, then there is no sense that you can make of this code without knowing ahead of time what name foo will be called with. Without being able to make such sense, compilation goes out the window -- but much more importantly, correctness (or generally, the meaning of your code) dies.
In my experience, this kind of pattern is much better handled with hash tables and similar devices.
using define-macro
#> (define-macro (dynamic-define varstr val)
`(define ,(string->symbol varstr) ,val))
#> (dynamic-define "variable" 123)
#> variable
123
using syntax-case
#> (define-syntax dynamic-define
(lambda (stx)
(syntax-case stx ()
((k varstr val)
(with-syntax ([var (datum->syntax-object
#'k
(string->symbol (syntax-object->datum #'varstr)))])
#'(define var val))))))
#> (dynamic-define "variable" 123)
#> variable
123

Scheme: match-lambda syntax error

I am writing a function annotate that uses match-lambda often with recursive calls to annotate. Here is one of the patterns and matches:
(`(,<param> . ,<params> (lambda (,<args>) ,<stmt> . ,<stmts>))
`(CLOSURE ENV ,(append (append `(,<param>) `(,<params>))`(,<args>)) (lambda (ENV) ,(map annotate `(,<stmt> . ,<stmts>)))))
I am getting a complaint that the first use of "." is illegal -- between "param" and "params" -- but I can't figure out why. This pattern and match doesn't get any complaints and seems very similar with regards to the first ".":
(`(λ (,<param1> . ,<params>) ,<stmt> . ,<stmts>)
`(CLOSURE ENV ,(map annotate `(,<param1> . ,<params>)) (λ (ENV) ,(map annotate `(,<stmt> . ,<stmts>)))))
Any advice is appreciated.
Thanks.
The . needs to be before the last element in the list (except for some Racket-specific syntax that you are not using). Remember that the general form of a list is (a b c . d), meaning (cons a (cons b (cons c d))). You might be able to use ,#<params> to match some elements in the middle of a list, but I am not sure about that.

Resources