Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Stupid closure question

31 views
Skip to first unread message

Jack Trades

unread,
Jun 16, 2009, 11:49:59 AM6/16/09
to
I'm pretty sure I already know the answer to this, but is there any
way I can create a closure that can be used without 'calling' it? For
example...

(define (my-list #!rest *args)
(let ((data *args))
(define (get) data)
(define (set aList) (set! data aList))
(define (len) (length data))
(lambda (#!rest args)
(if (null? args) (get)
(apply (case (car args)
((set) set)
((len) len)
(else get))
(cdr args))))))

(define a (my-list 1 2 3))
a
===> (1 2 3)
(a 'len)
===> 3

Jack Trades

Peter Michaux

unread,
Jun 16, 2009, 10:51:41 PM6/16/09
to
On Jun 16, 8:49 am, Jack Trades <JackTradesPub...@gmail.com> wrote:

> (define a (my-list 1 2 3))
> a
> ===> (1 2 3)
> (a 'len)
> ===> 3

So "a" is closure representing a message-passing-type object and one
of the messages to which it responds is 'len? If that is the case then
yes you can do that. SICP discusses this a great deal. Its index has
several entries for "message passing".

http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-17.html#%_idx_2486

Peter

Peter Keller

unread,
Jun 16, 2009, 11:11:10 PM6/16/09
to
Jack Trades <JackTrad...@gmail.com> wrote:
> (define a (my-list 1 2 3))
> a
> ===> (1 2 3)
> (a 'len)
> ===> 3

I don't believe you can do this, because it means that 'a' will have to
be a function AND a list at the same time which is a fundamental type
error in Scheme.

In this example, you'd have to fix the my-list generator to produce a function
that when a zero arity call happens, you return the list. In this example
your call will look like this:

> (define a (my-list 1 2 3))

> (a)


> ===> (1 2 3)
> (a 'len)
> ===> 3

I believe what you want to do can ultimately be possible, but you'd have
to implement your own scheme interpreter. It would have understand that
sometimes bare symbols are actually invocations of the procedures they
represent. I'm pretty sure it would be some varient of a lisp-2 style
evaluator due to the namespace manipulation of the symbol associated
with the closure.

Later,
-pete

Peter Michaux

unread,
Jun 16, 2009, 11:37:08 PM6/16/09
to
Peter Keller wrote:
> Jack Trades <JackTrad...@gmail.com> wrote:
> > (define a (my-list 1 2 3))
> > a
> > ===> (1 2 3)
> > (a 'len)
> > ===> 3
>
> I don't believe you can do this, because it means that 'a' will have to
> be a function AND a list at the same time which is a fundamental type
> error in Scheme.

Ahh yes. I didn't really pay attention to first result. Don't clojure
and arc allow for this sort of thing?

Peter

Aaron W. Hsu

unread,
Jun 17, 2009, 1:07:49 AM6/17/09
to
Peter Keller <psi...@merlin.cs.wisc.edu> writes:

>Jack Trades <JackTrad...@gmail.com> wrote:
>> (define a (my-list 1 2 3))
>> a
>> ===> (1 2 3)
>> (a 'len)
>> ===> 3

>I don't believe you can do this, because it means that 'a' will have to
>be a function AND a list at the same time which is a fundamental type
>error in Scheme.

You could mimick this behavior through the use of macros, but I don't
know what kind of trouble that would cause the OP.


--
Aaron W. Hsu <arc...@sacrideo.us> | <http://www.sacrideo.us>
"Government is the great fiction, through which everybody endeavors to
live at the expense of everybody else." -- Frederic Bastiat
+++++++++++++++ ((lambda (x) (x x)) (lambda (x) (x x))) ++++++++++++++

AndrewW

unread,
Jun 17, 2009, 8:33:38 AM6/17/09
to
Aren't you trying to be object oriented here ? If that's what you
want, have a look at Meroon or TinyCLOS.

As Peter says, SICP has a lot of detail on message passing that can do
the same.

More typical, would be to define the functions

my-list-get
my-list-set
my-list-len

e.g.

(my-list-len a)
==> 3

You can create a macro that will generate these functions, if they
follow a pattern, for your type.

or you could create a dot function analagous to Java or C++ a.len()
(. a 'len) that then passes the len message to a

Andrew

Jack Trades

unread,
Jun 17, 2009, 10:03:56 AM6/17/09
to
On Jun 16, 11:11 pm, Peter Keller <psil...@merlin.cs.wisc.edu> wrote:
> I believe what you want to do can ultimately be possible, but you'd
> have to implement your own scheme interpreter.

Thanks for the response. This is precisely what I thought. I'm
actually trying to write my first toy language, writing the AST in
Scheme. I was just trying to clean up the code a bit.

Jack Trades

Jack Trades

unread,
Jun 17, 2009, 11:07:12 AM6/17/09
to
On Jun 17, 8:33 am, AndrewW <and...@trailgauge.com> wrote:
> Aren't you trying to be object oriented here ?

Not particularly. Actually I'm trying to simplify implementing
polymorphic functions like length and index.

> As Peter says, SICP has a lot of detail on message passing
> that can do the same.
>
> More typical, would be to define the functions
>
> my-list-get
> my-list-set
> my-list-len

I'm actually fine with passing messages as (a 'len), however it adds
some complexity have to use (a) instead of just 'a' to get the list
that the closure holds. For example if I wanted to do an append
operation...

(define (my-list #!rest *args)
(let ((data *args))
(define (get)
data)

(define (last-pair)
(let loop ((d data))
(if (null? (cdr d)) d
(loop (cdr d)))))

(define (append! a-list)
(set-cdr! (last-pair) a-list))

;; Dispatch


(lambda (#!rest args)
(if (null? args) (get)
(apply (case (car args)

((append!) append!)
(else (error "Method not
implemented" args)))
(cdr args))))))

(define a (my-list 1 2 3))

(a 'append! '(4 5 6))
(a)
===> (1 2 3 4 5 6)
(a 'append! (my-list 7 8 9))
(a)
===> (1 2 3 4 5 6 . #<procedure (? #!rest args)>)


I'm mainly trying to keep complexity to a minimum, and figured that
using 'a' instead of (a) would be simpler than inserting tests or
forbidding the use of '(1 2 3), '#(1 2 3) and "abc".

Jack Trades

Jack Trades

unread,
Jun 17, 2009, 11:19:45 AM6/17/09
to
On Jun 17, 1:07 am, Aaron W. Hsu <arcf...@sacrideo.us> wrote:
> You could mimick this behavior through the use of macros...

Reader macros? I'm having trouble seeing how you could allow both
'a'
and (a 'len), even with macros. Note that I can already do (a), that
is what I'm trying to avoid though.

Jack Trades

Pascal J. Bourguignon

unread,
Jun 17, 2009, 11:30:09 AM6/17/09
to
Jack Trades <JackTrad...@gmail.com> writes:

> On Jun 17, 8:33 am, AndrewW <and...@trailgauge.com> wrote:
>> Aren't you trying to be object oriented here ?
>
> Not particularly. Actually I'm trying to simplify implementing
> polymorphic functions like length and index.
>
>> As Peter says, SICP has a lot of detail on message passing
>> that can do the same.
>>
>> More typical, would be to define the functions
>>
>> my-list-get
>> my-list-set
>> my-list-len
>
> I'm actually fine with passing messages as (a 'len), however it adds
> some complexity have to use (a) instead of just 'a' to get the list
> that the closure holds.

Well, in Common Lisp you could define a symbol-macro:

C/USER[94]> (defmacro define-list (name &rest args)
`(let ((list (list ,@args)))
(defun ,name (&optional message)
(ecase message
((nil) list)
((len) (length list))
#| ... |#
))
(define-symbol-macro ,name (,name))))
DEFINE-LIST
C/USER[95]> (define-list a 1 2 3)
A
C/USER[96]> a
(1 2 3)
C/USER[97]> (a 'len)
3
C/USER[98]>


To do the same in scheme you would have to redefine eval (it as
already mentionned that the solution is metalinguistic).

> I'm mainly trying to keep complexity to a minimum, and figured that
> using 'a' instead of (a) would be simpler than inserting tests or
> forbidding the use of '(1 2 3), '#(1 2 3) and "abc".

In practice, you don't use names such as a. With real names, such as:

(list-of-file-streams)
vs.
list-of-file-streams

the two additionnal characters don't look so mean anymore.


--
__Pascal Bourguignon__

Michele Simionato

unread,
Jun 17, 2009, 12:11:14 PM6/17/09
to

R6RS scheme has identifier macros:

(define (list-macro lst)
(make-variable-transformer
(lambda (x)
(syntax-case x (set! len)
((ls len) (length lst))
(ls #`'#,lst)))))

> (define z 1)
> (define-syntax a (list-macro (list z 2)))
> a
(1 2)
> (a len)
2

Pascal J. Bourguignon

unread,
Jun 17, 2009, 12:14:13 PM6/17/09
to
Jack Trades <JackTrad...@gmail.com> writes:

No, a true macro. But you'd have to use it to wrap expressions. That
macro could implement the symbol-macro notion.

(with-symbol-macro ((a (a)))
(define-symbol-macro b (b))
(+ (if (= a b)
(let ((a 42)) (+ b a))
(- b a))
((lambda (b) (* 2 b)) a)))

that macro would have to code-walk the body, to find where a and b are
references to the symbol macros and substitute them, but only there.
When a and b are "shadowed" by new bindings, it should let them alone.

So it would expand to:

(+ (if (= (a) (b))
(let ((a 42)) (+ (b) a))
(- (b) (a)))
((lambda (b) (* 2 b)) (a)))


Now of course, you have to ponder:

(a)

vs.

(with-symbol-macro ((a (a))) a)


Just kidding. You'd write:

(with-symbol-macro ()
(define-list small-numbers 1 2 3)
small-numbers)

--> (1 2 3)

--
__Pascal Bourguignon__

Abdulaziz Ghuloum

unread,
Jun 17, 2009, 12:30:15 PM6/17/09
to
Pascal J. Bourguignon wrote:

> [...]

> Well, in Common Lisp you could define a symbol-macro:

> [...]


>
> To do the same in scheme you would have to redefine eval

No you don't. Scheme has make-variable-transformer and
identifier-syntax.

Aziz,,,

Peter Keller

unread,
Jun 17, 2009, 12:37:05 PM6/17/09
to
Michele Simionato <michele....@gmail.com> wrote:
> R6RS scheme has identifier macros:
>
> (define (list-macro lst)
> (make-variable-transformer
> (lambda (x)
> (syntax-case x (set! len)
> ((ls len) (length lst))
> (ls #`'#,lst)))))
>
>> (define z 1)
>> (define-syntax a (list-macro (list z 2)))
>> a
> (1 2)
>> (a len)
> 2

I admit, that is pretty cool. I bet one could write a pretty mean
natural language processor using that idea....

-pete

Abdulaziz Ghuloum

unread,
Jun 17, 2009, 1:01:30 PM6/17/09
to
Michele Simionato wrote:

> R6RS scheme has identifier macros:
>
> (define (list-macro lst)
> (make-variable-transformer
> (lambda (x)
> (syntax-case x (set! len)
> ((ls len) (length lst))
> (ls #`'#,lst)))))
>
>> (define z 1)
>> (define-syntax a (list-macro (list z 2)))

This is not very kosher. What you want is something like:

(define-syntax define-list-macro
(syntax-rules ()
[(_ name value)
(begin
(define tmp value)
(define-syntax name
(make-variable-transformer
(lambda (stx)
(syntax-case stx (len set!)
[(x len) #'(length tmp)]
[(set! x v) #'(set! tmp v)]
[(x e* (... ...)) #'(tmp e* (... ...))]
[x (identifier? #'x) #'tmp])))))]))

(define-list-macro foo (list 1 2 3))

(printf "~s ~s\n" foo (foo len)) ;=> (1 2 3) 3

(set! foo (list 2 3))

(printf "~s ~s\n" foo (foo len)) ;=> (2 3) 2

(foo 1 2 3) ;=> &assertion in apply: (2 3) not a procedure.

Aziz,,,

wmfarr

unread,
Jun 17, 2009, 1:27:22 PM6/17/09
to
Jack,

On Jun 16, 11:49 am, Jack Trades <JackTradesPub...@gmail.com> wrote:
> I'm pretty sure I already know the answer to this, but is there any
> way I can create a closure that can be used without 'calling' it?  For
> example..

This is not exactly answering the question you asked, but it may help
you do what you want anyway. Why not try coming at the problem from
the opposite direction. You are asking for a closure which also holds
data; would a piece of data which is also an applicable function work
for you? For example, PLT Scheme has a way to define structures that
"masquerade" as procedures when you try to apply them. See
http://docs.plt-scheme.org/reference/procedures.html#(def._((lib._scheme/base..ss)._prop~3aprocedure))
for an example. It is not possible to use this approach with pre-
existing data structures, however, so you won't be able to make a list/
procedure hybrid, but it will work on any of your own data types.

Will

Jack Trades

unread,
Jun 17, 2009, 1:52:29 PM6/17/09
to
On Jun 17, 11:30 am, p...@informatimago.com (Pascal J. Bourguignon)
wrote:

> In practice, you don't use names such as a.  With real names, such as:
>
>  (list-of-file-streams)
>            vs.
>   list-of-file-streams
>
> the two additionnal characters don't look so mean anymore.

The "complexity" is not just the added (), it is also the
implementation of functions that use these data structures.
For example...

(define (append! a-list)
(set-cdr! (last-pair) a-list))

must become...

(define (append! a-list)
(if (procedure? alist)
(set-cdr! (last-pair) (a-list))
(set-cdr! (last-pair) a-list)))

to support both (my-list 1 2 3) and '(1 2 3). But this
implementation is still too simple as not all procedures
are the data structures that I'm expecting.

Jack Trades

Peter Michaux

unread,
Jun 17, 2009, 1:59:14 PM6/17/09
to
On Jun 17, 8:07 am, Jack Trades <JackTradesPub...@gmail.com> wrote:
> On Jun 17, 8:33 am, AndrewW <and...@trailgauge.com> wrote:
>
> > Aren't you trying to be object oriented here ?
>
> Not particularly.  Actually I'm trying to simplify implementing
> polymorphic functions like length and index.

So you want a function that will compute the lengths of various types
of data structures (e.g. lists or vectors)? Why not make a new len
function which will call length or vector-length as necessary? This
way you retain prefix notation and are open to a more CLOS-like system
in the future.

> (define (len o) (if (vector? o) (vector-length o) (length o)))
> (len #(1 2))
2
> (len '(1 2 3))
3

I can imagine that particular implementation is not too appealing if
you want to have other types of user-defined data structures use the
len function. See SICP starting in section 2.5.1 for a whole lot more
information.

Peter

Jack Trades

unread,
Jun 17, 2009, 2:03:51 PM6/17/09
to
On Jun 17, 12:14 pm, p...@informatimago.com (Pascal J. Bourguignon)
wrote:

> Jack Trades <JackTradesPub...@gmail.com> writes:
> > On Jun 17, 1:07 am, Aaron W. Hsu <arcf...@sacrideo.us> wrote:
> >> You could mimick this behavior through the use of macros...
>
> > Reader macros?  I'm having trouble seeing how you could allow both
> > 'a'
> > and (a 'len), even with macros.  Note that I can already do (a), that
> > is what I'm trying to avoid though.
>
> No, a true macro.  But you'd have to use it to wrap expressions.  That
> macro could implement the symbol-macro notion.
>
>     (with-symbol-macro ((a (a)))
>        (define-symbol-macro b (b))
>        (+ (if (= a b)
>              (let ((a 42)) (+ b a))
>              (- b a))
>           ((lambda (b) (* 2 b)) a)))

That looks pretty cool, I'll have to play around with that. In the
meantime I came up with this, that might work as I'm just using the
closure "behind-the-scenes" to simplify implementing polymorphic
functions.

(define-syntax (def x r c)
(let ((name (cadr x))
(val (caddr x))
(%begin (r 'begin))
(%define (r 'define))
(closure (string->symbol (string-append "__" (symbol->string
(cadr x)) "__"))))
`(,%begin
(,%define ,closure ,val)
(,%define ,name ((lambda (#!optional (x (,closure))) x))))))

(define (my-list #!rest *args)
(let ((data *args))
(define (get)
data)

(define (last-pair)


(let loop ((d data))
(if (null? (cdr d)) d
(loop (cdr d)))))

(define (append! a-list)
(set-cdr! (last-pair) a-list))

;; Dispatch


(lambda (#!rest args)
(if (null? args) (get)
(apply (case (car args)

((append!) append!)
(else (error "Method not
implemented" args)))
(cdr args))))))

(def a (my-list 1 2 3))


a ;;===> (1 2 3)

(__a__ 'append! '(4 5 6))
a ;;===> (1 2 3 4 5 6)

Thanks for the idea!

Jack Trades

Jack Trades

unread,
Jun 17, 2009, 2:21:39 PM6/17/09
to
On Jun 17, 12:11 pm, Michele Simionato <michele.simion...@gmail.com>
wrote:

> R6RS scheme has identifier macros:
>
> (define (list-macro lst)
>   (make-variable-transformer
>    (lambda (x)
>    (syntax-case x (set! len)
>      ((ls len) (length lst))
>      (ls #`'#,lst)))))
>
> > (define z 1)
> > (define-syntax a (list-macro (list z 2)))
> > a
> (1 2)
> > (a len)
>
> 2

That looks pretty cool! Unfortunately I'm using Chicken which, I
believe, doesn't support R6RS.

Jack Trades

Jack Trades

unread,
Jun 17, 2009, 2:33:03 PM6/17/09
to
On Jun 17, 1:59 pm, Peter Michaux <petermich...@gmail.com> wrote:

> So you want a function that will compute the lengths of various types
> of data structures (e.g. lists or vectors)? Why not make a new len
> function which will call length or vector-length as necessary?

That is how I originally implemented it.

> I can imagine that particular implementation is not too appealing if
> you want to have other types of user-defined data structures use the
> len function.

And that is why I'm trying to change the implementation. I still
plan to retain prefix notation externally. I'll only be using the
(var 'len) notation behind-the-scene of a (len var) function.

Jack Trades

Peter Michaux

unread,
Jun 17, 2009, 2:40:06 PM6/17/09
to

I don't think you need to implement it as (var 'len) behind the scenes
in order to have (len var) on the front end. You just need to
implement len as a dispatch function where various type-specific
implementations can be installed. See SICP starting in section 2.5.1

Aaron W. Hsu

unread,
Jun 17, 2009, 7:08:05 PM6/17/09
to
Jack Trades <JackTrad...@gmail.com> writes:

>On Jun 17, 12:11=A0pm, Michele Simionato <michele.simion...@gmail.com>


>wrote:
>> R6RS scheme has identifier macros:
>>
>> (define (list-macro lst)

>> =A0 (make-variable-transformer
>> =A0 =A0(lambda (x)
>> =A0 =A0(syntax-case x (set! len)
>> =A0 =A0 =A0((ls len) (length lst))
>> =A0 =A0 =A0(ls #`'#,lst)))))


>>
>> > (define z 1)
>> > (define-syntax a (list-macro (list z 2)))
>> > a
>> (1 2)
>> > (a len)
>>
>> 2

>That looks pretty cool! Unfortunately I'm using Chicken which, I
>believe, doesn't support R6RS.

I believe that Chicken has low level macros, and also has SYNTAX-CASE.
This means that you should have all the normal macro features necessary
to do this in Chicken. The basic idea is that you check whether the
macro was called as a macro "application" or by itself. You can do
this by either examining the syntax passed into the macro or using
existing features from things like SYNTAX-CASE.

I would be interested in seeing an ER or SC implementation of this
same concept.

Jack Trades

unread,
Jun 17, 2009, 9:06:58 PM6/17/09
to
On Jun 17, 2:40 pm, Peter Michaux <petermich...@gmail.com> wrote:

> I don't think you need to implement it as (var 'len) behind the scenes
> in order to have (len var) on the front end. You just need to
> implement len as a dispatch function where various type-specific
> implementations can be installed. See SICP starting in section 2.5.1
> for a whole lot more information.
>
> Peter

After reading some of the referenced SICP chapters, I really like this
idea. Though I'm not sure I completely understand it yet.

Thanks a lot, I'm off to study some more SICP now.

Jack Trades

0 new messages