I want to generate code in the following way:
(define (foo str)
(map (lambda (x) (* 100 x)) (hash-ref dd str)))
(define sth `(begin
(define dd (make-hash (list (cons "L" (list 1 2 3)))))
(hash-set! dd "H" ,(foo "L"))
dd))
(I will write sth to a sth.rkt file and execute it)
However, this doesn't work, because in the code for foo, it references on the dd identifier that is in the generated code, and therefore does not exist yet!
There is a way that I can generate code like this:
(define sth `(begin
(define dd (make-hash (list (cons "L" (list 1 2 3)))))
(hash-set! dd "H" (foo "L"))))
and prepend the function foo, but I don't really want that foo in my final file!
How can I work around this?
Are you sure that you're doing work that really requires code generation? Nothing in the example you've shown us requires it yet, as you can do something like this. In Racket:
#lang racket
;; When this file is required, dd will be provided to the outside.
(provide dd)
(define (foo str)
(map (lambda (x) (* 100 x)) (hash-ref dd str)))
(define dd (make-hash (list (cons "L" (list 1 2 3)))))
(hash-set! dd "H" (foo "L"))
This is a module that can be used by other programs. A module in Racket hides everything except for the items that are provided.
If you can explain why you want to do a code generation approach, maybe that will help us understand the question better. For code generation, a macro approach will probably work better than generating an s-expression and writing it to a file. See: http://docs.racket-lang.org/guide/macros.html for example.
Related
I want to make a program that makes a conversion simulating a for loop, for example:
orig value converted
1 2.2
2 4.4
...
199 437.8
So far, what I have done is the following:
(define (conv ini)
(if (> ini 199)
0
(begin(
(display (* ini 2.2))
(newline)
(conv (+ ini 1))))))
but when I want to run it I got the following error:
arity mismatch;
the expected number of arguments does not match the given number
expected: 1
given: 2
arguments...:
I see that my recursion call is fine, so I cannot get it which one is the problem.
The syntax of begin is (begin form ...) not (begin (form ...)): your function should be
(define (conv ini)
(if (> ini 199)
0
(begin
(display (* ini 2.2))
(newline)
(conv (+ ini 1)))))
(Or, if you are enamoured of a syntax like that, you could define
(define-syntax beguine
(syntax-rules ()
[(_ (form ...))
(begin form ...)]))
and then (beguine (...)) will work.)
...
(begin(
(display (* ini 2.2))
...))))
In your code you actually try to execute (OP ...), where OP is the value of (display ...), which for sure is not a function.
So I doubt a lot your output is the output of what you pasted in your question.
I'm using Chez Scheme and I'd like to introduce some top-level bindings based on the contents of a directory. The usage of this hypothetical macro might look like this:
(bind-files f "~/my-dir/")
;; Expanding to:
(begin (define f0 "~/my-dir/a.wav")
(define f1 "~/my-dir/b.wav"))
I'm getting comfortable with syntax-case, datum->syntax and with-syntax as described in the Scheme book's examples. But I can't imagine how one could create identifiers based on the result of something 'runtime-y' like (directory-list "~/") - is it even possible?
(By the way, this is for a live-coding musical application, so there's no need to comment that this is a bad idea for reliable software - it's for a very specific interactive context.)
You can use something like this macro:
#!r6rs
(import (rnrs) (chezscheme))
(define-syntax bind-file
(lambda (x)
(define (name&file k dir)
(define (->fn i)
(string->symbol (string-append "f" (number->string i))))
(let ((files (directory-list (syntax->datum dir))))
(datum->syntax k (do ((i 0 (+ i 1)) (files files (cdr files))
(r '() (cons (list (->fn i) (car files)) r)))
((null? files) r)))))
(syntax-case x ()
((k dir)
(string? (syntax->datum #'dir))
(with-syntax ((((name file) ...) (name&file #'k #'dir)))
#'(begin (define name file) ...))))))
(bind-file ".")
#|
;; depending on the number of files
f0 ... fn variables are defined.
|#
I am trying to write a scheme program that counts the number of if-statement a file containing code. I know how to read in the file but I don't know how to go about counting the number of if-statements.
This is very hard without actually implementing reducing the language to a more primitive form. As an example, imagine this:
(count-ifs '(let ((if +))
(if 1 2 3)))
; ==> 0
0 is the correct amount as if is a binding shadowing if and Scheme supports shadowing so the result of that expression is 6 and not 2. let can be rewritten such that you can check this instead:
(count-ifs '((lambda (if)
(if 1 2 3))
+))
; ==> 0
It might not look like an improvement, but here you can actually fix it:
(define (count-ifs expr)
(let helper ((expr expr) (count 0))
(if (or (not (list? expr))
(and (eq? (car expr) 'lambda)
(memq 'if (cadr expr))))
count
(foldl helper
(if (eq? (car expr) 'if)
(add1 count)
count)
expr))))
(count-ifs '((lambda (if)
(if 1 2 3))
(if #t + (if if if))))
; ==> 2
Challenge is to expand the macros. You actually need to make a macro expander to rewrite the code such that the only form making bindings would be lambda. This is the same amount of work as making 80% of a Scheme compiler since once you've dumbed it down the rest is easy.
A simple way to do it could be recursion structure like this:
(define (count-ifs exp)
(+ (if-expression? exp 1 0)))
(if (pair? exp)
(+ (count-ifs (car exp)) (count-ifs (cdr exp))))
0)))
But this might overcount.
A more correct way to do it would be to process the code by checking each type of expression you see - and when you enter a lambda you need to add the variables it binds to a shadowed symbols list.
Let's say I have the following two files:
;; demo.scm
(define-module (demo)
#:export (f))
(define (g x) 1)
(define (f x) (g x))
... and in the same directory:
;; use-demo.scm
(add-to-load-path ".")
(use-modules (demo))
(define (g x) (+ x 1))
(display (f 5))
(newline)
Running use-demo.scm in Guile (2), I get the output 1. So it looks like the function f has 'closed over' the function g that's defined in module demo. Is there any way to get around this? I really want to use the version of g that I've redefined in use-demo.scm.
OK, just for the record, I did some research and am posting the solution to this specific problem in case it helps someone.
The trick is to not redefine g locally, but rather to 'inject' the new function into the demo module's mapping of names to values.
(add-to-load-path ".")
(use-modules (demo))
(module-define! (resolve-module '(demo)) 'g
(lambda (x) (+ x 1)))
(display (f 5))
(newline)
If you have specific functions that you'd like to be able to override, you could make them configurable using parameters. This has some advantages:
You don't need to call reload-module to put the module back in its original configuration.
The changes only apply for the scope of the code which needs the modified behaviour.
It works properly when using multiple threads.
Obviously, the main disadvantage is that you need to add some boilerplate for each function that you want to allow to be overridden (although that's what hygienic macros are for, hehe).
The following code may work. I haven't run it.
;; demo.scm
(define-module (demo)
#:export (f))
(define (default-g x) 1)
(define p (make-parameter default-g))
(define (f x) ((p) x))
;; use-demo.scm
(add-to-load-path ".")
(use-modules (demo))
(define (my-g x) (+ x 1))
(parameterize ((## (demo) p) my-g)
(display (f 5))
(newline))
Obviously, if you can provide some additional information about what the application for this capability is, I might be able to suggest alternative approaches (there are a few others).
I have an experiment for my project, basically, I need to embedded some s-expression into the code and make it run, like this,
(define (test lst)
(define num 1)
(define l (list))
`#lst) ; oh, this is not the right way to go.
(define lst
`( (define num2 (add1 num))
(displayln num2)))
I want the test function be like after test(lst) in racket code:
(define (test lst)
(define num 1)
(define l (list))
(define num2 (add1 num)
(displayln num2))
How can I do this in racket?
Update
The reason I would like to use eval or the previous questions is that I am using Z3 racket binding, I need to generate formulas (which uses racket binding APIs), and then I will fire the query at some point, that's when I need to evaluate those code.
I have not figured out other ways to go in my case...
One super simple example is, imagine
(let ([arr (array-alloc 10)])
(array-set! arr 3 4))
I have some model to analyze the constructs (so I am not using racketZ3 directly), during each analyzing point, I will map the data types in the program into the Z3 types, and made some assertions,
I will generate something like:
At allocation site, I will need to make the following formula:
(smt:declare-fun arr_z3 () IntList)
(define len (make-length 10))
Then at the array set site, I will have the following assertions and to check whether the 3 is less then the length
(smt:assert (</s 3 (len arr_z3)))
(smt:check-sat)
Then finally, I will gather the formulas generated as above, and wrap them in the form which is able to fire Z3 binding to run the following gathered information as code:
(smt:with-context
(smt:new-context)
(define len (make-length 10))
(smt:assert (</s 3 (len arr_z3)))
(smt:check-sat))
This is the super simple example I can think of... making sense?
side note. Z3 Racket binding will crash for some reason on version 5.3.1, but it mostly can work on version 5.2.1
Honestly, I don’t understand what exactly you would like to achieve. To quote N. Holm, Sketchy Scheme, 4.5th edition, p. 108: »The major purpose of quasiquotation is the construction of fixed list structures that contain only a few variable parts«. I don’t think that quasiquotation would be used in a context like you are aiming at.
For a typical context of quasiquotation consider the following example:
(define (square x)
(* x x))
(define sentence
'(The square of))
(define (quasiquotes-unquotes-splicing x)
`(,#sentence ,x is ,(square x)))
(quasiquotes-unquotes-splicing 2)
===> (The square of 2 is 4)
Warning: if you're not familiar with how functions work in Scheme, ignore the answer! Macros are an advanced technique, and you need to understand functions first.
It sounds like you're asking about macros. Here's some code that defines test to be a function that prints 2:
(define-syntax-rule (show-one-more-than num)
(begin
(define num2 (add1 num))
(displayln num2)))
(define (test)
(define num1 1)
(show-one-more-than num1))
Now, I could (and should!) have written show-one-more-than as a function instead of a macro (the code will still work if you change define-syntax-rule to define), but macros do in fact operate by producing code at their call sites. So the above code expands to:
(define (test)
(define num1 1)
(begin
(define num2 (add1 num1))
(displayln num2)))
Without knowing the problem better, it's hard to say what the correct approach to this problem is. A brute force approach, such as the following:
#lang racket
(define (make-test-body lst)
(define source `(define (test)
(define num 1)
(define l (list))
,#lst))
source)
(define lst
`((define num2 (add1 num))
(displayln num2)))
(define test-source
(make-test-body lst))
(define test
(parameterize ([current-namespace (make-base-namespace)])
(eval `(let ()
,test-source
test))))
(test)
may be what you want, but probably not.