RLisp - Lisp naturally embedded in Ruby

On 7/25/06, Christian N. [email protected] wrote:

“Tomasz W.” [email protected] writes:

On 7/25/06, Christian N. [email protected] wrote:

Personally, I’d prefer setf.

Is setf used like that in any Lisp ?

Does Common Lisp count? :slight_smile:

Yeah, but setf changes variables in outside scope.
(setf a 2)
(defun foo ()
(setf a 3)
a
)
(foo) ; → 3
a ; → 3

I think it would be a huge win if variables were local to
the nearest lambda (or equivalent) by default, just like in Ruby.

BTW, did you consider adding hygienic macros?

I couldn’t understand them from the standard, and Paul Graham
keeps saying that they’re horrible, so I wasn’t very inclined to try :slight_smile:

Can you show some examples where they are better ?

Have a look at this:
http://people.csail.mit.edu/jhbrown/scheme/macroslides04.pdf

Thanks, it is very interesting.

My thoughts, as obtuse as they ever are:

  1. I have really liked Ruby for the very reason that I can often
    express algorithms from scheme/lisp directly in Ruby, but with a much
    more readable syntax. Yes, This will be controversial to the lambda
    devotees. However, my point is that Ruby can do this far easier than
    languages like C or Java.

  2. The ‘endless discussion’ does seem to be a feature of learning to
    program in Lisp. I suppose this may be because people who program in
    Lisp give a lot of thought to details of both design and
    implementation of software. However, I suspect that it may be that
    Lisp attracts a certain amount of what we used to call ‘rules lawyers’
    at the gaming table.

On 7/26/06, N Okia [email protected] wrote:

  1. I have really liked Ruby for the very reason that I can often
    express algorithms from scheme/lisp directly in Ruby, but with a much
    more readable syntax. Yes, This will be controversial to the lambda
    devotees. However, my point is that Ruby can do this far easier than
    languages like C or Java.

I agree that Ruby syntax is usually nicer.
However, it’s a lot more difficult to play with macros if you have
Ruby-like syntax.
S-expressions make it much easier :slight_smile:

On Thu, Jul 27, 2006 at 06:48:31AM +0900, N Okia wrote:

  1. The ‘endless discussion’ does seem to be a feature of learning to
    program in Lisp. I suppose this may be because people who program in
    Lisp give a lot of thought to details of both design and
    implementation of software. However, I suspect that it may be that
    Lisp attracts a certain amount of what we used to call ‘rules lawyers’
    at the gaming table.

While you may not want “rules lawyers” and “min-maxers” in your RPG
sessions, which are largely social events, there are some significant
advantages to be gained from such means of considering programming
problems. I’d rather have a “rules lawyer” writing my code than someone
who, conversely, doesn’t think the rules matter.

On 7/27/06, Christian N. [email protected] wrote:

the nearest lambda (or equivalent) by default, just like in Ruby.

That’s why one uses LET for local variables. :wink:

Can we macro around it or something, so that
(set-local-variable variable value) introduces a function-local variable
without increasing indentation level each time it’s being done?

I think it’s reasonable to write something like that (whatever the names
of set-local-variable operator is):

(defun veclen (x y)
(set-local-variable x2 (* x x))
(set-local-variable y2 (* y y))
(set-local-variable z2 (+ x2 y2))
(sqrt z2)
)

Tomasz W. wrote:

No, that’s just because a is global here. Shadow it by a local variable:

I think it would be a huge win if variables were local to

(defun veclen (x y)
(set-local-variable x2 (* x x))
(set-local-variable y2 (* y y))
(set-local-variable z2 (+ x2 y2))
(sqrt z2)
)

Such a macro would be a strange beast indeed. The problem is that
indentation level actually reflects lexical scope, which means that
set-local-variable would have to find the environment for the function
veclen and change this after it was defined. What you could do if the
nesting is bad for you is to introduce CL’s aux variables:
(defun veclen (x y &aux (x2 (* x x)) (y2 (* y y)) (z2 (+ x2 y2)))
(sqrt z2))

This is of course just syntactic sugar, but it works and is
standardized. I recommend you do this, keep setf/setq for changing the
variables, but leave let alone.


Ola B. (http://ola-bini.blogspot.com)
JvYAML, RbYAML, JRuby and Jatha contributor
System Developer, Karolinska Institutet (http://www.ki.se)
OLogix Consulting (http://www.ologix.com)

“Yields falsehood when quined” yields falsehood when quined.

“Tomasz W.” [email protected] writes:

Yeah, but setf changes variables in outside scope.
(setf a 2)
(defun foo ()
(setf a 3)
a
)
(foo) ; → 3
a ; → 3

No, that’s just because a is global here. Shadow it by a local
variable:

(defun foo ()
(let (a)
(setf a 3)
a))

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

I think it would be a huge win if variables were local to
the nearest lambda (or equivalent) by default, just like in Ruby.

That’s why one uses LET for local variables. :wink:

“Tomasz W.” [email protected] writes:

(set-local-variable z2 (+ x2 y2))
(sqrt z2)
)

Well, you can’t quite do that but you can easily do something like
this:

(defun veclen (x y)
(easy-local-progn
(local x2 (* x x))
(local y2 (* y y))
(local z2 (+ x2 y2))
(sqrt z2)
)
)

Or:

(defun-with-local veclen (x y)
(local x2 (* x x))
(local y2 (* y y))
(local z2 (+ x2 y2))
(sqrt z2)
)

(There may also be a way to override the standard meaning of “defun”
to have it do what your “defun-with-local” macro does, but I’d
recommend strongly against overriding standard parts of the language
like that)

On 7/27/06, Daniel M. [email protected] wrote:

(set-local-variable y2 (* y y))
(local y2 (* y y))
(local z2 (+ x2 y2))
(sqrt z2)
)

So, how would such a macro look like ?

Tomasz W. wrote:

(defun veclen (x y)
(defun-with-local veclen (x y)
(local x2 (* x x))
(local y2 (* y y))
(local z2 (+ x2 y2))
(sqrt z2)
)

So, how would such a macro look like ?

You would have to do a code-walker (with all the glory such a thing
brings), find all places where you have local and more or less replace
them with let and let* each time you find one.


Ola B. (http://ola-bini.blogspot.com)
JvYAML, RbYAML, JRuby and Jatha contributor
System Developer, Karolinska Institutet (http://www.ki.se)
OLogix Consulting (http://www.ologix.com)

“Yields falsehood when quined” yields falsehood when quined.

“Tomasz W.” [email protected] writes:

So, how would such a macro look like ?

Well, 1) This is ruby-talk, not comp.lang.lisp, and 2) I don’t
actually know lisp.

But how hard can it be, right? … (1.5 hours later) …

Okay, try this:

(defun local-expander (bodylist)
(cond ((null bodylist) '())
((and (consp (car bodylist)) (eq (caar bodylist) 'local))
`((let ,(loop for x on (cdar bodylist)
by #'cddr
collect (list (car x) (cadr x)))
,@(local-expander (cdr bodylist)))))
(t (cons (car bodylist) (local-expander (cdr bodylist))))))

(defmacro progn-with-local (&rest body)
`(progn ,@(local-expander body)))

(defmacro defun-with-local (name args &rest body)
`(defun ,name ,args ,@(local-expander body)))

Then, you can do:

(defun-with-local pythag (x y)
(local x2 (* x x))
(local y2 (* y y))
(local z2 (+ x2 y2))
(sqrt z2))

Actually, you could even shorten that slightly to:

(defun-with-local pythag (x y)
(local x2 (* x x) y2 (* y y))
(local z2 (+ x2 y2))
(sqrt z2))

But I think that hurts the readability.

Note that you don’t need to supply an initial value in the (local)
bit. Also, a (local) declaration will shadow references that follow
it, but not those that precede it. For example:

  • (defvar a 'top)
    A
  • a
    TOP
  • (progn-with-local (setf a 'before) (local a) (setf a 'after))
    AFTER
  • a
    BEFORE

On 7/27/06, Daniel M. [email protected] wrote:

`(progn ,@(local-expander body)))
(sqrt z2))
Wow, I’m genuinely impressed by this macro.
Now I’ll try to understand it … :smiley: