Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - Kazimir Majorinc

#16
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.
#17
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.
#18
newLISP in the real world / Re: Function composition?
December 20, 2011, 01:23:22 PM
I wrote the post "http://kazimirmajorinc.blogspot.com/2010/02/composition-of-functions-or-macros.html">Composition of functions and macros" on my blog.



((composition 'f1 ... 'fn) _ _ _) = (f1 (f2 ... (fn _ _ _)))



If there was no significant change from February 2010, you should be able to cut and paste whole post in your editor and it should work.
#19
Yes, it does.
#20
newLISP in the real world / Re: variable capture?
November 15, 2011, 03:35:22 PM
My experience is that dynamic scope almost never causes the problems. I think it happened to me something like two times in last four years, and then I fixed it easily. I have two functions in my library, protect1 and protect2 I'm using to check whether that is the case. I write something like


(define (my-function ...) ...) ; using variables x, y, z
(protect1 'my-function '(x y)) ; in case I want overshadowing of z, say, it is some global counter


and that protect1 will change the names of the variables in something like my-function.x, my-function.y, my-function.z, so accidental overshadowing with variables from other functions is impossible. There is no performance penalty for doing that. For example:


(set 'set-protected1
  (lambda(function/macro-name definition-code variables)
    (set function/macro-name
      (expand definition-code
              (map (lambda(x)
                        (list x (sym (string function/macro-name "." x))))
                        variables)))))
                       
(set 'protect1 (lambda(function/macro-name variables)
                 (set-protected1 function/macro-name
                                 (eval function/macro-name)
                                 variables)))

;-------------
; your code with additional 'protection'

    (define-macro (dolist-while)
      (letex (var (args 0 0)
              lst (args 0 1)
              cnd (args 0 2)
              body (cons 'begin (1 (args))))
        (let (res)
          (catch (dolist (var lst)
                   (if (set 'res cnd) body (throw res)))))))
                   
     (protect1 'dolist-while '(var lst cnd body res))              

    (define (test1 a-list)
      (dolist-while (x a-list (!= x 'd)) (println x)))

    (define (test2 lst)
      (dolist-while (x lst (!= x 'd)) (println x)))

    (test1 '(a b c d e f))
    (test2 '(a b c d e f))
;----------------


It works.



Here is how your macro looks like after 'protection':


(lambda-macro ()
 (letex (dolist-while.var (args 0 0) dolist-while.lst (args 0 1) dolist-while.cnd
   (args 0 2) dolist-while.body
   (cons 'begin (1 (args))))
  (let (dolist-while.res)
   (catch
    (dolist (dolist-while.var dolist-while.lst)
     (if (set 'dolist-while.res dolist-while.cnd)
      dolist-while.body
      (throw dolist-while.res)))))))


In most cases, I do not use that protect1, only if my program has error I cannot find, then I test whether it is caused by name overshadowing. But almost never it is. I use it "just in case" when I write functions for library. Particularly, I used protect1 to protect protect1.



This solution is equivalent to officially recommended use of contexts.



Very rarely, accidental overshadowing might happen between two instances of the same function or macro (if function calls itself recursively.) It is particularly severe form of the name overshadowing, it cannot be solved with protect1 or with contexts, and for that purpose, I have protect2. It is very sophisticated function, and its use has high price in performances, but the fact is, I never needed it, neither once. It sits in my library 'just in case'. For years now. Discussion on this forum has shown that noone actually had that problem at all.



With very little experience, one learns how to prevent accidental overshadowing, and problems are very rare in practice.
#21
-

Few posts on http://lmf-ramblings.blogspot.com">http://lmf-ramblings.blogspot.com



http://lmf-ramblings.blogspot.com/2011/09/why-do-i-still-use-newlisp.html">Why do I still use Newlisp

http://lmf-ramblings.blogspot.com/2011/08/i-am-not-afraid-to-admit-that-ive-used.html">I am not afraid to admit that I've used Lisp for real work

http://lmf-ramblings.blogspot.com/2011/09/well-that-was-fast.html">Well, that was fast

http://lmf-ramblings.blogspot.com/2011/08/talk-about-proving-my-point.html">Talk about proving my point



Who is LMF? I didn't know for this blog until today.
#22
Whither newLISP? / Proposal: forever & doforever
September 01, 2011, 01:56:04 AM
(forever ...) := (while true ...)

(doforever(i) ...) := (begin (setf i 0)(while true (++ i) ...)).



Probably (dotimes(i 9223372036854775807)...) is good enough for doforever.
#23
newLISP newS / Re: blog post about newLISP
August 18, 2011, 12:11:23 AM
Newlisp is recently mentioned in positive context in following blog posts as well:



http://blog.fogus.me/2011/08/14/perlis-languages/">http://blog.fogus.me/2011/08/14/perlis-languages/

http://dorophone.blogspot.com/2011/08/survey-of-syntactic-extension.html">http://dorophone.blogspot.com/2011/08/s ... nsion.html">http://dorophone.blogspot.com/2011/08/survey-of-syntactic-extension.html
#24
Whither newLISP? / Why do you use sym?
July 03, 2011, 05:17:19 PM
I'm trying to make review of situations where sym is useful. I use it


[*]for generation of expressions processed by programs. For example, here:

http://kazimirmajorinc.blogspot.com/2011/01/enumeration-of-lambda-expressions.html">http://kazimirmajorinc.blogspot.com/201 ... sions.html">http://kazimirmajorinc.blogspot.com/2011/01/enumeration-of-lambda-expressions.html


  • [*]for alpha-conversion, i.e. prevention of symbol clashes when calling macros. It is equivalent of use of (gensym) in other Lisp dialects in macro definition. For example, here

    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



  • [*]for bulk definitions of functions or macros using same algorithm, for example, defining operators setq+, setq-, setq* ... such that (setq+ a b) <=> (setq a (+ a b)),  (setq- a b) <=> (setq a (- a b)) ... For example, here

    http://kazimirmajorinc.blogspot.com/2008/06/assignment-macro-beast-unleashed.html">http://kazimirmajorinc.blogspot.com/200 ... ashed.html">http://kazimirmajorinc.blogspot.com/2008/06/assignment-macro-beast-unleashed.html



  • [*]for simulation of hash tables - in some other language, I'd use B["011101"], in Newlisp I just use symbol B011101.  For example, here

    http://kazimirmajorinc.blogspot.com/2009/11/relatively-short-propositional-formulas.html">http://kazimirmajorinc.blogspot.com/200 ... mulas.html">http://kazimirmajorinc.blogspot.com/2009/11/relatively-short-propositional-formulas.html
  • [/list]


    Do you have some other example of use of sym?
    #25
    Whither newLISP? / Re: Tail call optimization
    June 22, 2011, 08:24:06 AM
    No.
    #26
    I announce my presentation at Sunday, 5. June 2011, 18h, http://hackerspaces.org/wiki/Hacklab_in_mama">Hacklab "mama", Preradoviceva 18, Zagreb.

    with topic



    [size=110]The program that calculates the tangent on the graph of the function in Newlisp as example of "code is data" approach in Lisp. [/size]



    Very elementary, classical Lisp example with few Newlisp specificities, suitable for those who want to familiarize with or rethink basic Lisp ideas.
    #27
    John Shutt is author of Kernel, experimental Lisp dialect that attempts to combine fexprs with lexical scope.



    http://fexpr.blogspot.com/">http://fexpr.blogspot.com/
    #28
    http://blog.fogus.me/2011/05/03/the-german-school-of-lisp-2/">http://blog.fogus.me/2011/05/03/the-ger ... of-lisp-2/">http://blog.fogus.me/2011/05/03/the-german-school-of-lisp-2/
    #29
    Great! If you're in Croatia, you'll probably visit Zagreb, and I'll be glad to drink some beer with colleague. If you'll have free evening and will, we might arrange some (your) lecture or presentation of your work on NL or anything related to computers in http://hackerspaces.org/wiki/Hacklab_in_mama">Hacklab and then go to some beer ...



    I'm looking forward ...
    #30
    Without using contexts, demonstrated by johu, if you want pass by reference, you should really pass the reference of the structure (not the structure itself), and make your function dereference it:



    (set 'x '(0 1 2 (3 4)))

    (define (destruct lst) (setf ((eval lst) 3 0 0) 1)) ; eval is dereference

               

    (println x) ; =>(0 1 2 (3 4))

    (setf (x 3 0) 4)

    (println x) ; =>(0 1 2 (4 4))

    (destruct 'x) ; passes symbol x, which is reference of the list stored as value of x

    (println x) ; =>(0 1 2 (1 4))




    Another way for dereference (if you want to do it once in larger blocks) is
    (define (destruct lst)
               (letex((lst lst))
                  (setf (lst 3 0 0) 1)
                  (setf (lst 3 0 1) 2)))