Can I create a macro so that I can call sequence- functions with a s-? Hence, I should be able to write s-length, s-filter and s-map instead of sequence-length, sequence-filter and sequence-map. Thanks.
You can use filtered-in from racket/require to perform this sort of transformation. Here’s a simple example:
#lang racket
(require racket/require
(filtered-in (λ (name) (regexp-replace #rx"^sequence-" name "s-"))
racket/sequence))
(s-ref '(1 2 3) 1)
If you find yourself using this sort of thing often, it wouldn’t be too hard to write a require transformer that would expand to filtered-in:
#lang racket
(require (for-syntax racket/require-transform
syntax/parse)
racket/require)
(define-syntax reprefix-in
(make-require-transformer
(syntax-parser
[(_ original-prefix:id new-prefix:id require-spec:expr ...)
#:with replacer (string-append "^" (regexp-quote (symbol->string (syntax-e #'original-prefix))))
#:with replacement (symbol->string (syntax-e #'new-prefix))
(expand-import #'(filtered-in (λ (name) (regexp-replace (regexp 'replacer) name 'replacement))
(combine-in require-spec ...)))])))
Then you can use it like this:
(require (reprefix-in sequence- s- racket/sequence))
(s-ref '(1 2 3) 1)
Yes there is. To versing levels of cludgyness.
The way I highly recommend you do, however, is to use rename-in To rename each of these functions on import. So for example, your code would look like:
#lang racket
(require (rename-in racket/sequence
[sequence-length s-length]
[sequence-map s-map]
[sequence-filter s-filter]
...))
There are other more advanced ways to do this that do not require you to explicitly list out each identifier, using module->exports, regexp-match, format-id, and make-require-transformer. But this seems to brittle to me and you're better off being explicit about which names you want to rename.
Related
I'm in a bigger code and I need to do it like:
file_1.rkt :
#lang racket
(provide define-type types-ref)
(require syntax/parse/define)
(begin-for-syntax
(define types (make-hasheq)))
(define-syntax-parser define-type
[(_ id type)
(hash-set! types (syntax->datum #'id) (syntax->datum #'type))
#'(void)])
(define-syntax-parser types-ref
[(_ id)
(writeln (hash-ref types (syntax->datum #'id)))
#'(void)])
file_2.rkt :
#lang racket
(provide (all-defined-out))
(require "file_1.rkt")
(define-type Atom Symbol)
(types-ref Atom)
out:
Symbol
file_3.rkt :
#lang racket
(require "file_1.rkt" "file_2.rkt")
(types-ref Atom)
out:
; hash-ref: no value found for key
; key: 'Atom
; Context (plain; to see better errortrace context, re-run with C-u prefix):
; /Applications/Racket v8.0/collects/syntax/parse/define.rkt:20:4
; /Applications/Racket v8.0/collects/syntax/wrap-modbeg.rkt:46:4
; /...
It seems that for each syntax expansion types is instantiated again.
I need to share the same types for different files. What can I do?
Do you really need to store the information in a hash table like that? A simpler way is to actually define id in define-type, so that you can properly provide it, and the other modules can properly require it.
It looks like you want define-type to occur at compile-time, so you can use define-syntax to create the binding, and use syntax-local-value to reference it.
#lang racket
(provide define-type types-ref)
(require syntax/parse/define)
(define-syntax-parser define-type
[(_ id type)
#'(define-syntax id (quote type))])
(define-syntax-parser types-ref
[(_ id)
(writeln (syntax-local-value #'id))
#'(void)])
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.
I'm trying to write the Scheme equivalent of this CL code:
(defmacro alias (new-name prev-name)
`(defmacro ,new-name (&rest args)
`(,',prev-name ,#args)))
;; Sample use:
(alias co concatenate)
My aim is to be able to use shorthand names for symbol and function names like:
(alias sa string-append)
(sa "ok" "not ok")
To do that I've tried this but it didn't work:
(define-syntax alias (new-name prev-name)
`(define-syntax ,new-name (#!rest args)
`(,',prev-name ,#args)))
Any help is appreciated. Thank you.
You can do this easily with a syntax-rules macro that defines another syntax-rules macro:
(define-syntax alias
(syntax-rules ()
((_ new-name prev-name)
(define-syntax new-name
(... (syntax-rules ()
((_ arg ...)
(prev-name arg ...))))))))
The trickiest thing is this macro is the use of ... to escape nested uses of ....
However, this is not necessarily the best way to do this. The best way probably depends on your precise Scheme implementation, as Scheme is less a language and more a family of languages. Writing portable Scheme is usually not very useful.
If your scheme supports R6RS syntax-case and cognates (say, guile or chez scheme), identifier-syntax is the most direct way of implementing what you want:
(define-syntax new-name (identifier-syntax old-name))
Thus:
(define-syntax new-display (identifier-syntax display))
(new-display "hello\n")
Edit: I see you are using chicken. In that case you can use er-macro-transformer to reproduce your defmacro solution (this works with chicken-4.10.0 at any rate):
(define-syntax alias
(er-macro-transformer
(lambda (exp r c)
(let ([new-name (cadr exp)]
[old-name (caddr exp)])
`(define-syntax ,new-name
(ir-macro-transformer
(lambda (exp i c)
`(,',old-name ,#(cdr exp)))))))))
By the way, in Common Lisp you can make an alias a real function, not a macro, by settings symbol-function of a symbol denoting an alias like this:
CL-USER> (defun foo (name)
(format nil "Hello ~A!~%" name))
FOO
CL-USER> (setf (symbol-function 'bar)
#'foo)
#<INTERPRETED-FUNCTION FOO>
CL-USER> (bar "Bob")
"Hello Bob!
"
I'm making a random sentence generator using Scheme (Pretty Big), and I'm having trouble defining temporary variables. I want to make something like this:
<NOUN1> <VERB1> <NOUN2> <but> <NOUN2> <VERB1> <NOUN2> <also>
Example: Sharks eat fish, but fish eat fish also.
I have word lists, and functions to choose a word from said list. Then, I use append to create a function. I am able to do:
(define (sentence)
(append (getNoun) '(and) (getNoun) (getVerb)))
However, I am unable to figure out a way to temporarily define a variable.
I have this so far:
(define (sentence1)
(append (getNoun)
(lambda (verb getVerb)
(noun getNoun))
(verb) (noun) '(but) (noun) (verb) (noun)))
Hints/Help please?
You are looking for let.
http://docs.racket-lang.org/reference/let.html
Here is an example usage:
(define (my-proc age)
(let ([age-plus-10 (+ age 10)])
(printf "age is ~a" age)
(printf "age-plus-10 is ~a" age-plus-10)))
Notice how we can temporarily define age-plus-10 and then use it later.
(defspel game-action (command subj obj place &rest rest)
`(defspel ,command (subject object)
`(cond ((and (eq *location* ',',place)
(eq ',subject ',',subj)
(eq ',object ',',obj)
(have ',',subj))
,#',rest)
(t '(i cant ,',command like that.)))))
Thats the code from http://www.lisperati.com/actions.html for the 'macro defining macro'. I can't seem to convert it appropriately to scheme. Can someone explain to me the process of creating this same sort of thing in Scheme?
This kind of macro is actually much simpler in Scheme, since you can do it all with define-syntax-rule (in standard Scheme code you will need define-syntax + syntax-rules). You basically do the same thing, minus the whole quote/unquote mess.
(defspel (game-action command subj obj place rest ...)
(defspel (command subject object)
(cond [(and (eq? *location* 'place)
(eq? 'subject 'subj)
(eq? 'object 'obj)
(have 'subj))
rest ...]
[else '(i cant command like that.)])))
And since this is actually most of the code, I ported the whole thing to PLT -- see the post on the mailing list.