Is there the name conflict of lambda in newlisp?

Started by iNPRwANG, December 24, 2011, 12:10:02 AM

Previous topic - Next topic

iNPRwANG

I'm sorry for my english.  While I run under codes, I can not understand why the result is 10 unless the myfun's lambda parameter use the variable "a" defined of myfun2. And the common lisp get the right results :30.







(define (myfun2 fun)
(let ((a 20))
(apply fun '())
)
)

(define (myfun)
(let ((a 10))
(myfun2
(lambda ()
(setq a 30))
)
a
)
)
       
(print (myfun))

(exit)

Kazimir Majorinc

#1
Newlisp uses dynamic scope. That means that application of (lambda()(setq a 30)) doesn't refer to binding of a on the place of definition of (lambda()(setq a 30)), in this case in myfun, but on binding of a in the place of application, i.e. in myfun2.



It is how it was in original, McCarthy's Lisp. Then Scheme introduced lexical scoping and Common Lisp followed (although CL supports dynamic scope if you http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Body/dec_special.html">declare local variables as special). It is one of the most controversial issues in Lisp.
http://kazimirmajorinc.com/\">WWW site; http://kazimirmajorinc.blogspot.com\">blog.

iNPRwANG

#2
Thanks a lot!

I'v read the common lisp special, and I'v understand the newlisp uses the dynamic scope, the common lisp could use (declare (special xxx)) to let a variable's scope be dynamic.



But, had newlisp got a solution to avoid the name conflict of dynamic scope?  Such as, I often use the variable name of "tmp", and how to avoid the name confilct of another function.



I'm thinking a way about could a function to construct a function-local-context to store the function local variable, and auto destroy while the function end. (by modify the newlisp's design : P )The code like this:



(define (myfun2 fun)
   (let ((a 20))
      (apply fun '())
      )
   )

(define (myfun)
   (let ((myfun:a 10))  
      (myfun2
         (lambda ()
            (setq myfun:a 30))
         )
      myfun:a
      )
   )
       
(print (myfun))
(exit)



conan

#3
I'm not sure I fully understand what you're trying to achieve. However I can tell you that you avoid name conflicts by using http://www.newlisp.org/downloads/newlisp_manual.html#contexts">contexts.

Kazimir Majorinc

#4
The conflict might happen only if you pass "free variable" around; that is the case with


(lambda()(setf a 3))
but not with


(lambda()(let((a 4))(setf a 3))).
As long as one does not pass free variables around he is safe. The problem most frequently occurs with Newlisp macros (actually, fexprs). These rely on free variables. If one defines ifnt, inverse of if with


(define-macro (ifnt condition else then)
     (if (eval condition)
         (eval then)
         (eval else)))

then all variables used in, for example,


(ifnt (< a b) (setf a 4)(setf b 4))
are passed to ifnt as free variables. In that case the problem is exactly the same as in Common Lisp macros, where the solution is in use of gensyms. Newlisp doesn't have gensym, but one can easily define his own.


(define (gensym)
   (inc gensym-counter)
   (sym (append "G-" (string gensym-counter))))

However, in almost all cases, use of gensym is overkill. I defined two functions for myself: set-protected1 and set-protected2.


(set-protected1 'ifnt (lambda(c e t)(if (eval c)(eval t)(eval e)))
                      '(e c t))

will actually produce code lambda-expression like


(lambda([ifnt.c] [ifnt.e] [ifnt.t])
    (if (eval [ifnt.c])
        (eval [ifnt.t])
        (eval [ifnt.e])))

Which is "safe" because it uses unique names. Good news is that you do not need to use my set-protected1 or to write your own - as conan wrote, Newlisp provides "contexts" which do that for yourself. Look on this REPL communication.


> (context 'ifnt)
ifnt
ifnt> (define-macro (ifnt:ifnt c e t)(if (eval c) (eval t) (eval e)))
(lambda-macro (c e t)
 (if (eval c)
  (eval t)
  (eval e)))
ifnt> (context 'MAIN)
MAIN
> (ifnt (< 2 3) ">=" "<")
"<"
> ifnt:ifnt
(lambda-macro (ifnt:c ifnt:e ifnt:t)
 (if (eval ifnt:c)
  (eval ifnt:t)
  (eval ifnt:e)))
>

It is probably exactly what you need. It is also recommended approach by designer of the language.



Neither set-protected1 nor contexts are "safe" in one very special case - if recursive macro passes one of its variables as free variable from one instance of the macro to another instance of the same macro, where it will be accessed inside new binding of the same variable. It is so rare case that I never encountered something like that, and as it was discussed on this forum, it turned that noone reported that he experienced that problem.



If problem is still interesting from theoretical point of view, you can look at my blogpost



http://kazimirmajorinc.blogspot.com/2009/12/symbols-as-sexprs.html">http://kazimirmajorinc.blogspot.com/200 ... exprs.html">http://kazimirmajorinc.blogspot.com/2009/12/symbols-as-sexprs.html



It contains implementation of set-protected1 and set-protected2, last does exactly what you proposed "function to construct a function-local-context to store the function local variable, and auto destroy while the function end", which turns to be relatively complicated from technical point of view. I must warn it is not how typical "production code" looks like, it is how it looks if one wants to play with Lisp.
http://kazimirmajorinc.com/\">WWW site; http://kazimirmajorinc.blogspot.com\">blog.

iNPRwANG

#5
Thanks, this solution of define function as context default functor can avoid name conflict in most case.  : )

Lutz

#6
Here is a function you can use to define functions as default functors in their own space:


(define (def-static s body)
      (def-new 'body (sym s s)))


and use like this:


> (def-static 'acc (fn (x) (inc sum x)))
acc:acc
> (acc 1)
1
> (acc 1)
2
> (acc 1)
3
> (acc 5)
8
> acc:acc
(lambda (acc:x) (inc acc:sum acc:x))
>


fn is the same as lambda but quicker to write.

iNPRwANG

#7
Quote from: "Lutz"Here is a function you can use to define functions as default functors in their own space:


(define (def-static s body)
      (def-new 'body (sym s s)))


and use like this:


> (def-static 'acc (fn (x) (inc sum x)))
acc:acc
> (acc 1)
1
> (acc 1)
2
> (acc 1)
3
> (acc 5)
8
> acc:acc
(lambda (acc:x) (inc acc:sum acc:x))
>


fn is the same as lambda but quicker to write.


Thank you for the nice solution!

tumble

#8
Thanks, Lutz.  I really like the syntax of that definition (def-static).

jopython

#9
Lutz,



Is it possible to use the def-static with lambda-macro?

Lutz

#10
You can do this:



> (def-static 'mysetq (lambda-macro (p1 p2) (set p1 (eval p2))))
mysetq:mysetq
> (mysetq x 123)
123

and this is what got generated:



> mysetq:mysetq
(lambda-macro (mysetq:p1 mysetq:p2) (set mysetq:p1 (eval mysetq:p2)))
>


There is also another definition of 'def-static' which can be used like 'define', but is not suitable for macros:



http://www.newlisp.org/code/def-static.html">http://www.newlisp.org/code/def-static.html



also linked from here:



http://www.newlisp.org/index.cgi?page=Differences_to_Other_LISPs">http://www.newlisp.org/index.cgi?page=D ... ther_LISPs">http://www.newlisp.org/index.cgi?page=Differences_to_Other_LISPs

jopython

#11
Thank you.

Maybe "def-static" should  become a newlisp 'builtin'