Traversing Scheme function as a list
Asked Answered
P

7

8

Isn't it possible to treat functions in Scheme as any other list?

Basically, what I want do to is something like this:

(define (foo) "hello")

(cdr foo)  ; or similar, should return the list ((foo) "hello")

I've found a similar discussion about this, and I feel a bit disappointed if this is not possible with Scheme. If so, why is this impossible? Is it possible in other lisps?

EDIT: Changed (cdr 'foo) to (cdr foo) -- it was misleading. I'm asking, why can't I access a function as a list?

Pinder answered 6/3, 2010 at 17:59 Comment(1)
Also found some interesting notes: cs.brown.edu/pipermail/plt-scheme/2006-May/013052.htmlPinder
V
3

I have often wanted to be able to do the same thing csl. Below is a quick example of how you could go about doing this in mzscheme.

DrScheme 4.2

(module qdefine mzscheme
  (provide ;(all-from-except mzscheme let)
   (rename define olddefine)
   (rename quote-define define)
   (rename quote-cdr cdr)
   (rename quote-car car))

  (define define-list '())
  (define define-list-add 
    (lambda (key value)
      (set! define-list (cons `(,key ,value) define-list))))

  (define-syntax quote-define
    (syntax-rules ()
      ((_ (pro-name args ...) body ...) 
       (begin
         (define (pro-name args ...) body ...)
         (define-list-add pro-name  '((pro-name args ...) body ...))))
      ((_ pro-name pro) (begin
                          (define pro-name pro)
                          (define-list-add pro-name 'pro)))

      ))

  (define quote-cdr (lambda (lst)
                      (if (procedure? lst)
                          (cdr (cadr (assoc lst define-list)))
                          (cdr lst))))

  (define quote-car (lambda (lst)
                      (if (procedure? lst)
                          (car (cadr (assoc lst define-list)))
                          (car lst))))
  )
(require 'qdefine)

(define testfunc (lambda (args) args))
(cdr testfunc)
(car testfunc)

(define (testfunc2 test) 'blah)
(cdr testfunc2)
(car testfunc2)

(define testlist '(1 2 3 4 5 6 'a))
(cdr testlist)
(car testlist)

Outputs:

((args) args)
lambda
('blah)
(testfunc2 test)
(2 3 4 5 6 'a)
1
>
Violetvioleta answered 6/3, 2010 at 23:9 Comment(2)
Anyone know how to do it in other scheme implementations?Pinder
Depending on implementation I think you can do something similar with defmacro or Syntatic closures. I would like to have the macro equivalent of (define blah (lambda ...))(define blah (lambda (...) new code (blah ...))), but I have not found a scheme implementation that allows for a straight forward way of doing this.Violetvioleta
T
2

Your define form is not a function but a function definition. In fact, it is a shorthand for

(define foo
  (lambda ()
    "hello"))

Lambda can be thought of as a "compiler invocation". In this case, it produces a function which returns that string. Define then binds this function to the symbol 'foo.

Compare this to

(define foo "hello")

which binds just the string to the symbol 'foo. What would (cdr foo) return?

Now, it is imaginable that some Scheme implementation actually saves or has the option to save the lambda form when binding a function to a symbol. You will have to check the documentation, but the kind of pure interpretation this implies surely would have an impact on performance.

If you manage to get this, though, it will return the lambda form, not the define form.

Treachery answered 6/3, 2010 at 18:42 Comment(1)
Excellent explanation! Wouldn't it be possible to create my own define-form that both compiled the code (through eval) and kept the source around? That would be helpful.Pinder
F
2

MIT Scheme has the ability to do this. (If you really want, comment on this and I'll give you the code. I had to find some undocumented functions to make it happen.)

However, it's not in the Scheme language definition, so implementations don't have to allow it. The reason for this is that in order to make functions faster, a good Scheme implementation will modify the functions. This means both rewriting them in a different language (either machine code or something fairly low-level) and taking out any bits you don't need - for instance, the + function must in general check whether its arguments are numbers, and if so, what sort of numbers, but if your function is a loop which calls +, you can just check once at the beginning, and make the function a lot faster.

Of course, you could still keep the lists around without too much trouble, even with all of these things. But if you tried to modify the lists, how would it work?

(Again, you could make it work. It would just be more work for implementers, and since it's not usually used in programs, most people probably just don't want to bother.)

Felting answered 6/3, 2010 at 18:56 Comment(2)
Sure, I'd be happy to get the code. Maybe post it online (gist/pastebin) ?Pinder
I'm sorry - I thought I had it, but I just looked and I couldn't find it. I made it by basically downloading the mit-scheme sources, finding how they represented interpreted procedures, and using a few of the functions in that file which happened to be available at the REPL, even though they probably shouldn't have been.Felting
M
2

In guile,

guile> (define (foo bar) 'baz)
guile> (procedure-source foo)
(lambda (bar) (quote baz))
guile> (cdr (procedure-source foo))
((bar) (quote baz))
guile>

Mann answered 12/3, 2010 at 1:16 Comment(0)
R
1

'foo evaluates to a symbol, you can't take the CDR of a symbol.

What you may want to do is (cdr foo), but this does not work. The value of a FOO is a procedure, not a list.

Rosemaryrosemond answered 6/3, 2010 at 18:14 Comment(4)
Yeah; I'm asking why I can't cdr a procedure.Pinder
because the procedure is not a list. You can cdr only lists. the procedure could be a bunch of machine instructions.Rosemaryrosemond
That's not a very satisfying answer -- you could say the same for lists, because you don't really know how lists are represented in memory.Pinder
@csl: CDR is defined for conses and lists. Nothing more. So CDR works for lists. Since a procedure is not a list, it won't work. A procedure is something else.Rosemaryrosemond
K
1

You might be able to access the function as a list using pp or pretty-print. That said, you might also need to run your code in debug mode. This is very implementation dependent however. I know it can work in Gambit-C.

Kremenchug answered 6/3, 2010 at 18:35 Comment(0)
K
1

(define (foo) ...) produces a compiled object, and it's a value - a procedure.
You cannot iterate over it because it is not an s-expression.

Like what other suggested, you should check out your programming environment and see
if it has any facilities for such tasks.

Koenig answered 6/3, 2010 at 18:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.