Setting alist with dynamically evaluated variable name in Guile Scheme - scheme

Currently, I have the following alist:
(define globals '((objects test)))
The name of its variable is stored in another alist:
(define test '((loc globals) (other properties)))
I would like to easily retrieve the objects list in globals. I first tried this code.
(assoc 'objects
(cadr (assoc 'loc
test)))
However, that spit out an error:
ERROR: In procedure assoc: Wrong type argument in position 2 (expecting association list): globals
I searched and found this question, so I tried using eval.
(assoc 'objects
(eval '(cadr (assoc 'loc
test))
(interaction-environment)))
However, that spit out the same error as above! Does anyone know how to call assoc with the right argument?
EDIT (2014-10-27 21:27 EST): Thank you for all of the solutions. Unfortunately, the submitted examples will likely not work on the full code:
(define-syntax object
(syntax-rules ()
((_ name prop prop* ...)
(begin
(define name '(prop prop* ...))
(let* ((parent (cadr (assoc 'loc name)))
(objref (cdr (assoc 'objects parent))))
(set! parent
(assoc-set! parent
'objects
(append objref '(name)))))))))
(object my-object
(loc globals)
(name "Harry")
(desc "My Object"))

Try this:
(define globals '((objects test)))
(define test (list (list 'loc globals) '(other properties)))
; alternatively: (define test (list `(loc ,globals) '(other properties)))
(assoc 'objects
(cadr (assoc 'loc test)))
=> '(objects test)
In this case, we don't want to create a list of symbols such as this:
'(loc globals)
What we want, is a list whose second element is another list called globals:
(list 'loc globals)
Alternatively (as pointed by Chris in the comments) we can use quasiquoting to make explicit that we do want an actual value in the list, not that we forgot to quote an item:
`(loc ,globals)
UPDATE
This is a different problem, you should mention the whole context from the beginning. The assoc-set! procedure is still missing from the question, but you can try this to see if it's what you need:
(define-syntax object
(syntax-rules ()
((_ name prop prop* ...)
(begin
(define name '(prop prop* ...))
(let* ((parent (eval (cadr (assoc 'loc name)))) ; use Guile's eval
(objref (cdr (assoc 'objects parent))))
(set! parent
(assoc-set! parent
'objects
(append objref '(name)))))))))

Related

General memoization in Scheme

i have been assigned homework to make a general memoization procedure in scheme, so far it works on procedures that take one argument, but fail on what it seems to be the last argument when provided with more than 1. It also fails to memoize procedures that take no arguments.
Any help would be greatly appreciated.
(define mem
(lambda (mem-it func)
(let ((table (make-table) )(func-store func))
(cond
((equal? mem-it 'memoize)
(lambda args
(if (null? args)
func
(let ((prev (lookup args table)))
(or prev
(let ((result (apply func args)))
(insert! args result table)
result))))))
((equal? mem-it 'unmemoize)
(func-store))
(else (display "No Such command"))))))
This is what i have so far
(define (test-proc . args)
(display "computing test-proc of ")
(display args)
(newline)
(if (null? args)
0
(+ (expt (- 42 (car args)) 2)
(apply test-proc (cdr args)))))
And here is the test procedure provided
The error occurs when i try to run the following test
(set! test-proc (mem 'memoize test-proc))
(test-proc 40 41 42 43 44)
Here are the other procedures used
(define (make-table)
(list '*table*))
(define (lookup key table)
(let ((record (assoc key (cdr table))))
(and record (cdr record))))
(define (insert! key value table)
(let ((record (assoc key (cdr table))))
(if record
(set-cdr! record value)
(set-cdr! table
(cons (cons key value) (cdr table))))))
Your memoizarion procedure has a feature where it returns the implementation procedure when no arguments are passed:
((mem 'memoize test-proc)) ; ==> test-proc
The base case of your test procedure will never hit because of this feature thus for (test-proc 1) you can substitute it with the expression (+ 1681 test-proc) which will signal an error since test-proc is not a number.
It's better to use unique magic values:
(define +GET-PROC+ (list "get-proc"))
(test-proc +GET-PROC+) ; ==> original-test-proc
Since we are making a list it's is eq? that data only. In R6RS you can refrain from exporting so that code that uses memoization doesn't really have access to mess with it. All lists that look like it eg ("get-proc") won't be eq? so it can be used as an argument without getting the original procedure.
Since you are not using a standard hash procedure from (rnrs hashtables) or SRFI-69 it's not possible for me to check it but since you are using a list as key your hashtable must use equal? as test. This is often a source of frustration when using hash tables in most lisps.

Scheme Function Maker

I've been working on this procedure in Scheme (specifically Pretty Big) and I've hit a brick wall. What I'm trying to do is create a procedure that can create other procedures or functions. For the most part I think I'm on the correct track.
(define (function-maker function-specs)
(let* [(specs (map cdr function-specs))
(name (caar specs))
(args (cadr function-specs))
(body (cdr(cdr function-specs)))]
(eval(list 'define name
(list 'lambda args body)))))
Current Output:
Above is the current output and I'll explain to the best of my knowledge what is happening. The input takes in three arguments essentially. A name, to name the function. Arguments for the function and finally the body of the function.
The three arguments are then listed together and then it's supposed to create a new function. The picture above shows the error that I'm reaching. Thanks for the help!
To see what's happening, get rid of the eval and examine the list:
(define (function-maker function-specs)
(let* [(specs (map cdr function-specs))
(name (caar specs))
(args (cadr function-specs))
(body (cdr(cdr function-specs)))]
(list 'define name
(list 'lambda args body))))
> (function-maker '((name: add5) (x) (+ x 5)))
'(define add5 (lambda (x) ((+ x 5))))
As you can see, there are too many parentheses in the body, so you're attempting to use the resulting number as a procedure.
You want
(body (car (cdr (cdr function-specs))))
or
(body (caddr function-specs))

is it possible to implement "define-macro" in mit-scheme

After reading this page. I find it hard to memorize how to use define-syntax in place of define-macro, so I want to implement define-macro (or at least find some equivalent) in mit-scheme.
Here is my (problematic) implementation:
(define-syntax define-macro
(rsc-macro-transformer
(let ((xfmr (lambda (macro-name macro-body)
(list 'define-syntax macro-name
(list 'rsc-macro-transformer
(let ((m-xfmr macro-body))
(lambda (e r)
(apply m-xfmr (cdr e)))))))))
(lambda (e r)
(apply xfmr (cdr e))))))
(define-macro my-when
(lambda (test . branch)
(list 'if test (cons 'begin branch))))
(my-when #t
(begin
(display "True")
(newline)))
And the REPL complained:
;The object (lambda (test . branch) (list (quote if) test (cons (quote begin) branch))) is not applicable.
I'm new to scheme and have no idea about what is wrong, can someone help me out?
Firstly, you should learn to use quasiquotation, so your macro is easier to read. Like this:
(define-macro (my-when test . branch)
`(if ,test
(begin ,#branch)))
More seriously, though, this is pretty easy to write using syntax-rules, and you really should vastly prefer it over define-macro.
(define-syntax-rule (my-when test branch ...)
(if test
(begin branch ...)))
Oh, you haven't seen define-syntax-rule before? It's a simple macro you can use for writing a one-clause define-syntax macro, and it's defined so:
(define-syntax define-syntax-rule
(syntax-rules ()
((define-syntax-rule (name . pattern) template)
(define-syntax name
(syntax-rules ()
((name . pattern) template))))))
Notice how, using define-syntax-rule, simple macros become really, really easy to write. Here's another example:
(define-syntax-rule (let ((name value) ...)
expr ...)
((lambda (name ...)
expr ...)
value ...))
If you really need define-macro semantics, you can get a reasonable approximation in mit-scheme like so:
(define-syntax define-macro
(syntax-rules ()
((define-macro (name . args) body ...)
(define-syntax name
(rsc-macro-transformer
(let ((transformer (lambda args body ...)))
(lambda (exp env)
(apply transformer (cdr exp)))))))))
You could then define my-when as:
(define-macro (my-when test . branch)
`(if ,test (begin ,#branch)))

type of (car list) in scheme

If I define a list in scheme like this
(define list '(when i type I 1 23 4 2))
What's the type of the thing (car list) returns? And another question is: can I convert it to the string?
In the list shown in the question, the car is the symbol 'when. You can verify it, but first let's change the name of the list to something else, for avoiding a name collision with the built-in list procedure:
(define lst '(when i type I 1 23 4 2))
(symbol? (car lst))
> #t
The #t (true) in the last line shows that indeed the first element is a symbol. If you need to convert it to a string, simply do this:
(symbol->string (car lst))
> "when"
EDIT :
Answering the question in the comments, this should work:
(define (isvariable? symbol)
(and (symbol? symbol)
(eqv? (string-ref (symbol->string symbol) 0)
#\?)))

Call to defmacro with a quoted symbol

I have this data structure (basically):
(setq ssm-list '(tasklist
((id . "10525295")
(name . "Inbox")
(sort_order . "0"))))
This works for getting the name:
(defun ssm-list-get-prop (list prop)
(cdr (assoc prop (car (cdr list)))))
(ssm-list-get-prop slack-one-list 'name)
What'd I like is to create a macro that will create a defun with the name ssm-list-name (or ssm-list-id) as there are actually a lot more properties in the list.
So I tried this:
(defmacro ssm-list-prop-defun (field)
`(defun ,(intern (concat "ssm-list-" field))
(one-list)
(cdr (assoc ,field (car (cdr one-list))))))
(ssm-list-prop-defun 'name)
(ssm-list-prop-defun 'id)
But the last two calls failed miserably with (wrong-type-argument characterp quote) I tried putting symbol-name in the macro but that didn't help.
Is there a way to accomplish this?
You're very close, minor edits gets you a working solution. The problem is that you're mixing symbols and strings. This will work:
(defmacro ssm-list-prop-defun (field)
;; note that concat operates on strings
`(defun ,(intern (concat "ssm-list-" field))
(one-list)
;; note that you need a symbol here, so quote the
;; result of the call to intern
;; and, if you're always using symbols,
;; might as well use assq
(cdr (assq ',(intern field) (car (cdr one-list))))))
;; pass in a string
(ssm-list-prop-defun "name")
And here's the variant that uses a symbol:
;; variant that works off a symbol
(defmacro ssm-list-prop-defun (field)
`(defun ,(intern (concat "ssm-list-" (symbol-name field)))
(one-list)
(cdr (assq ',field (car (cdr one-list))))))
(ssm-list-prop-defun name)
I think you want to read about defstruct in the cl package: (info "(cl) Structures") (or http://www.gnu.org/software/emacs/manual/html_node/cl/Structures.html#Structures)

Resources