Re: conc: unexpected results
Apologies for bothering everyone with this. It took some research (there is surprising little discussion of the function online or even in most books), but I at least understand how it works now. It seems that it is not often used in everyday programming: "It is a good idea to leave the use of NCONC, RPLACA, RPLACD, and DELETE to risk-loving programmers. Unless desperate for time or space saving, using them just leads to unnecessary bugs. "--Lisp (Winston, Horn) P. 117 /Lindsay On Thu, Feb 9, 2017 at 5:21 PM, Lindsay John Lawrence < lawrence.lindsayj...@gmail.com> wrote: > I tried conc to an empty list on both 32 and 64 bit versions of picolisp > I even installed SBCL just to try the similar 'nconc' on that platform. > > The results are consistent for all of them. > I just don't understand why Is it simply 'standard', historical > reasons? because of the way evaluation works? > > As it is, I would not be able to build a list 'destructively' without > conditional logic for the initial empty list. > conc works as expected when M is not empty. i.e M is rewritten. > > > # > # Could also use NIL to represent the empty list ( > http://software-lab.de/doc/ref.html#nilSym) > : (setq M '() N '(A B C)) > -> (A B C) > : (conc M N) > -> (A B C) > : M > -> NIL > : N > -> (A B C) > > # This is even weirder to me... > # Again, I expected M, not N, to be rewritten > : (setq M NIL N '(A B C) L '(1 2 3)) > -> (1 2 3) > : (conc M N L) > -> (A B C 1 2 3) > : M > -> NIL > : N > -> (A B C 1 2 3) > : L > -> (1 2 3) > # - > > /Lindsay > > >
Re: conc: unexpected results
I tried conc to an empty list on both 32 and 64 bit versions of picolisp I even installed SBCL just to try the similar 'nconc' on that platform. The results are consistent for all of them. I just don't understand why Is it simply 'standard', historical reasons? because of the way evaluation works? As it is, I would not be able to build a list 'destructively' without conditional logic for the initial empty list. conc works as expected when M is not empty. i.e M is rewritten. # # Could also use NIL to represent the empty list ( http://software-lab.de/doc/ref.html#nilSym) : (setq M '() N '(A B C)) -> (A B C) : (conc M N) -> (A B C) : M -> NIL : N -> (A B C) # This is even weirder to me... # Again, I expected M, not N, to be rewritten : (setq M NIL N '(A B C) L '(1 2 3)) -> (1 2 3) : (conc M N L) -> (A B C 1 2 3) : M -> NIL : N -> (A B C 1 2 3) : L -> (1 2 3) # - /Lindsay
Re: box? on address
On Thu, Feb 9, 2017 at 6:13 PM, Christopher Howardwrote: > Hi, I was just trying to understand... > > : (box? (box (4 5 6))) > -> $384375304 > : (box? $384375304) > -> NIL > : (car $384375304) > -> 4 > > Shouldn't (box? $384375304) be non-NIL? > As Danilo said box? evaluates its arguments and that's the reason to return NIL because a list is not an anonymous symbol The same happens with the call to car, car evaluates its arguments so you get the car of the list To allow box? to deal with anonymous symbol you must quote it If you type the $-number representing the anonymous symbol in the pil prompt you see its value, in your case: : $384375304 -> (4 5 6) The result of evaluating the anonymous symbols and that explains the behaviour of your calls to both box? and car, : (car $384375304)# = (car (4 5 6)) -> 4 but what if you call car with real anonymous symbol (quoting it to prevent evaluation)? : (car '$384375304) -> (4 5 6) why? my guess is anonymous symbols store its value in the car of its cell
Re: box? on address
hi, Lets talk about t ransient s ymbols from this two links: http://software-lab.de/doc/ref.html#transient http://pastebin.com/AsuveCFY On Thu, Feb 9, 2017 at 7:13 PM, Christopher Howardwrote: > Hi, I was just trying to understand... > > : (box? (box (4 5 6))) > -> $384375304 > : (box? $384375304) > -> NIL > : (car $384375304) > -> 4 > > Shouldn't (box? $384375304) be non-NIL? > > -- > Christopher Howard, Computer Assistant > Alaska Satellite Internet > 3239 La Ree Way, Fairbanks, AK 99709 > 907-451-0088 or 888-396-5623 (toll free) > fax: 888-260-3584 > mailto:christop...@alaskasi.com > http://www.alaskasatelliteinternet.com > -- > UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe >
conc: unexpected results
conc does not rewrite N if N is an empty list. # 1. : (let (N '()) (conc N '(A))) -> (A) # 2 : (let (N '()) (conc N '(A)) N) -> NIL # 3. : (let (N '(NIL)) (conc N '(A)) N) -> (NIL A) # 4. : (let (N '()) (setq N (conc N '(A))) N) -> (A) In #2 above, I was expecting N to be (A) If N is not empty, as in #3 it works as expected, or I can force the assignment, as in #4... which shouldn't be necessary. Originally I wanted to do: : (let (N '()) (for X 10 (conc N '(A))) N) -> NIL # expected '(A A A A A A A A A A) ..and this goes into never land. [kill -9] (let (N '()) (for X 10 (setq N (conc N '(A N) /Lindsay
Re: box? on address
`box?' evaluates it's argument. In this case it is `lst' ``(4 5 6)''. BTW I didn't know `print'ed box can be `read' back. For example ``$0'' does have a name, but `print'ed one does not. It makes no sense to me. On 2/9/17, Christopher Howardwrote: > Hi, I was just trying to understand... > > : (box? (box (4 5 6))) > -> $384375304 > : (box? $384375304) > -> NIL > : (car $384375304) > -> 4 > > Shouldn't (box? $384375304) be non-NIL? > > -- > Christopher Howard, Computer Assistant > Alaska Satellite Internet > 3239 La Ree Way, Fairbanks, AK 99709 > 907-451-0088 or 888-396-5623 (toll free) > fax: 888-260-3584 > mailto:christop...@alaskasi.com > http://www.alaskasatelliteinternet.com > -- > UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe > -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: binding free symbols in a lambda definition
Hi Alex, > However, a function call is about the most expensive thing in PicoLisp. It > interprets the parameter list (X), saves the old value of X, evaluates (not X) > and restores the value of X. (de null..) was really unnecessary here :) I just wrote it for completeness as part of the book exercise and after my earlier confusion regarding 'NIL, NIL, '()... Nice to know about 'def' when I need a bit of syntax sugar though ! I am starting to get the hang of the basics here I think. I've been spending a bit of time bench'ing some of the recursive functions and trying to eliminate the recursion or use a built-in function, as you have often shown. # my append : (de cuius (X Y) (cond ((not X) Y) (T (cons (car X) (cuius (cdr X) Y) : (bench (let (N ()) (for X 1 (setq N (cuius N '(NIL (length N))) 2.983 sec -> 1 # ...with nond : (de cuius (X Y) (nond (X Y) (NIL (cons (car X) (cuius (cdr X) Y) : (bench (let (N ()) (for X 1 (setq N (cuius N '(NIL (length N))) 2.644 sec -> 1 # ... neither of the above are even close in performance to ... # append : (bench (let (N ()) (for X 1 (setq N (append N '(NIL (length N))) 0.548 sec -> 1 # cons : (bench (let (N '()) (for X 1 (setq N (cons NIL N))) (length N))) 0.000 sec -> 1 # conc : (bench (let (N (list)) (for X (conc N (list))) (length N))) 0.067 sec -> 1 # -- or -- : (bench (let (N ()) (setq N (need 1)) (length N))) 0.000 sec -> 1. Interestingly, I was expecting conc to be faster then (setq..(cons..). At least in this case, it was not. /Lindsay
box? on address
Hi, I was just trying to understand... : (box? (box (4 5 6))) -> $384375304 : (box? $384375304) -> NIL : (car $384375304) -> 4 Shouldn't (box? $384375304) be non-NIL? -- Christopher Howard, Computer Assistant Alaska Satellite Internet 3239 La Ree Way, Fairbanks, AK 99709 907-451-0088 or 888-396-5623 (toll free) fax: 888-260-3584 mailto:christop...@alaskasi.com http://www.alaskasatelliteinternet.com -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: binding free symbols in a lambda definition
If `and' and `or' is renamed, or just aliased, to `then' and `else', there is little need left for `if' and `cond' >:) . -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: binding free symbols in a lambda definition
Hi Lindsay, > I missed to include it... >(de null (X) (not X)) OK! :) However, a function call is about the most expensive thing in PicoLisp. It interprets the parameter list (X), saves the old value of X, evaluates (not X) and restores the value of X. Therefore I would recommend (def 'null not) This gives zero overhead :) > I'll have to work with nond a bit more to get how/when use that. Good. Just use the opposite conditions. Instead of (cond ((not A) (foo)) ((not B) (bar)) (T (mumble)) ) you write (nond (A (foo)) (B (bar)) (NIL (mumble)) ) ♪♫ Alex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: binding free symbols in a lambda definition
Hi Alex, I missed to include it... (de null (X) (not X)) Thanks! for the suggestions. I tried the pairlis alternatives. Much better. 'extract' will be very useful. I'll have to work with nond a bit more to get how/when use that. /Lindsay On Thu, Feb 9, 2017 at 3:17 AM, Alexander Burgerwrote: > Hi Lindsay, > > > # pairlis2: gives a list of pairs of corresponding elements > > # of the lists x and y, and appends this to the list a. > > # (pairlis '(A B C) '(1 2) () ) -> ((A . 1) (B . 2)) > > > > (de pairlis2 (X Y A) > >(cond > > ((null X) A) > > ((null Y) A) > > (T > > (cons > > (cons (car X) (car Y)) > > (pairlis2 (cdr X) (cdr Y) A) ) ) ) ) > > Sorry, I have not tested, but 'null' should be undefined. You could > replace it > with 'not'. But then 'nond' is better than 'cond', avoiding it completely > (see > discussion here in this list). > > > In general, using recursion here is quite an overkill. A simpler form > could be > >(de pairlis (X Y A) > (conc (mapcar cons X Y) A) ) > > or, if you want to handle the case where the first list is longer than the > second, > >(de pairlis (X Y A) > (conc > (extract > '((A B) (and A B (cons A B))) > X > Y ) > A ) ) > > ♪♫ Alex > -- > UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe >
Re: binding free symbols in a lambda definition
Picolisp continues to astonish me with its 'Principle of Least Astonishment'... using @ variable arguments is much nicer. /Lindsay # using pairlis2 and sublis from prior email... (de curri2 @ (let (Fun (next) Args (rest) Par (pairlis2 (car Fun) Args) dropP '((X Y) (cond ((null Y) X) (T (dropP (cdr X) (cdr Y))) ) ) ) (list (dropP (car Fun) Args) (car (sublis Par (cdr Fun))) ) ) ) -> curri2 : (setq Fun (curri2 '((X Y) (+ X Y -> ((X Y) (+ X Y)) : (Fun 1 99) -> 100 : (setq Fun (curri2 '((X Y) (+ X Y)) 1) ) -> ((Y) (+ 1 Y)) : (Fun 99) -> 100 : (setq Fun (curri2 '((X Y) (+ X Y)) 1 99) ) -> (NIL (+ 1 99)) : (Fun) -> 100
Re: binding free symbols in a lambda definition
Hi Andrés, thanks for the "curri" examples! > Sorry for the large email and even while pretending to be a clarifying text > it is not :( I think it was :) > Also don't want to give an image of pretending to arrange picolisp's flaw > design, it is absolutely not, not only I don't have the needed > understanding of picolisp nor the knowledge to do so but I consider > picolisp a pretty good design with very smart decisions. What I trying to No worry, I didn't get that impression. I knew these use cases, but until now never had practical situations where they seemed useful. As we saw, they can be handled with the 'curry' function if necessary, but I believe that PicoLisp has better mechanisms - like fexprs and unlimited number of arguments to most functions - to *directly* express the programmer's intentions. For example, > (mapcar ((curri **) 2) (2 3 4)) > # equivalent to (mapcar '((X) (** 2 X)) (2 3 4)) would be written shorter in PicoLip (mapcar ** (2 3 4) (2 .)) -> (4 9 16) > (setq lstLen ((curri mapcar) length)) # equivalent to (de lstLen > (lst) (mapcar length lst)) > (lstLen '((1) (2 3 4) (2 3))) (mapcar length '((1) (2 3 4) (2 3))) -> (1 3 2) > yes, I have to study your classiCurry function to clearly understand how it > works and yes maybe I'm a bit confused about dynamic binding usefulness due > to my static binding background You are not alone :) I try to explain more, perhaps it is also useful for other readers here. > (let N 4 (print N)) > > binds symbol N to value 4 inside print expression and so it prints 4, this > is what we expect of let binding behaviour Yes, though instead of "binds .. inside print" I would say "binds N to 4 inside the body of 'let'. A lexically binding system would indeed magically replace N in the print expression, but in PicoLisp N is bound to 4 during the *time* this let body runs. > same for this code: > > (let N 4 (+ 1 N)) > > we expect to return 5 Yes. > In a coherent way we expect this code: > > (let N 4 ((X) (+ X N))) # erroneus code, I know it! > > to return a function which adds 4 to its parameter (and it would do it if > it doesn't throw a X undefined error) No. This code is not wrong per se, it just does not return a function. As you know, Lisp evaluates expressions by taking the CAR as a function, and the CDR as arguments to that function. So when the body of 'let' is executed, (X) is expected to evaluate to a function, and the result of evaluating (+ X N) is passed to that function. There might even be situations where the above expression makes sense. The problem is more that '+' expects a number, so let's modify it slightly: : (de X () # Define 'X' to return a function println ) -> X : (let N 4 ((X) (+ (size X) N))) 6 -> 6 What happens? (X) evaluates to the function 'println' (the function *pointer* to be exact, as 'println' is a primitive): : X -> (NIL println) : (X) -> 22966530359 # Function pointer to the code of 'println' Then (+ (size X) N) is evaluated : (size X) -> 2 and passed to be printed. It prints 6. > But here the problem is we cannot write an anonymous function (a lambda) > this way, we *must* quote it: > > (let N 4 '((X) (+ X N))) No, you *did* write an anonymous function. It ignored the value of N though. In PicoLisp, code and data are absolutely equivalent. Thus, the list ((X) (+ X N)) is, first of all, data. A list of two lists. The fact that it might be interpreted somewhere else as a function doesn't matter. The point is that in our head we want to return a function, but here we have a chunk of data to be returned. Thus it must be quoted, to inhibit the evaluation as seen above. > but now the quoting has the effect of not evaluating the lambda and thus > preserving it from let symbol binding, this is an undesiderable effect in > my opinion Yes, because there is no lexical (static) binding. All symbols are evaluated solely at runtime. If you need the values statically, you have to do it explicitly, e.g. with 'curry' or simply with list operations: (let N 4 (list '(X) (list '+ 'X N))) -> ((X) (+ X 4)) Voila, the expected function is returned. > So what to do? (from here I'm just reasoning loud) well, the key is to > separate function evaluation from function calling, what if there would be > a mark for type function? No, this would be a big drawback. You lose the equivalence of code and data. The term "function evaluation" is the same as "function calling". What you mean is "function building", i.e. the process of building a function from data, to be evaluated (or called) later. > 1- read the whole let expression > 2- read-macros get executed inmmediately (really I think this is part of > step 1) > 3- perform the bindings in "let prog" expression > 4- evaluate the "let prog" in te context set by let bindings (due to step 3) Exactly. And this is what happens. The point is just that the bindings
Re: binding free symbols in a lambda definition
I've enjoyed the discussion. Curry is a common idiom in the javascript world (my current day job) so it was very interesting to explore it here. Being relatively new to picolisp I have a lot to learn about built-in functionality so exploring these ideas, with feedback from Alex and others more familiar, is very productive! Below is YAC (Yet another curry)... A simplication, that would allow more natural writing, would be to use @ instead of the current Args list of provided params to curri2. I am still getting the hang of that... /Lindsay I apologise if it is a lot of code to post here, but this was also great opportunity to apply a bit of what I have been learning from the "Lisp 1.5 Programmer's Manual" # note: pairlis2, sublis are functions are adapted from the manual to implement 'curri2' # pairlis2: gives a list of pairs of corresponding elements # of the lists x and y, and appends this to the list a. # (pairlis '(A B C) '(1 2) () ) -> ((A . 1) (B . 2)) (de pairlis2 (X Y A) (cond ((null X) A) ((null Y) A) (T (cons (cons (car X) (car Y)) (pairlis2 (cdr X) (cdr Y) A) ) ) ) ) # 'A is an assoc list ((u . v)..). # sublis: treats the u's as variables # when they occur in Y, and substitutes the # corresponding v's from the pair list (de sublis (A Y) (let (sub2 '((A Z) (cond ((null A) Z) ((= (caar A) Z) (cdar A)) (T (sub2 (cdr A) Z)) ) ) ) (cond ((atom Y) (sub2 A Y)) (T (cons (sublis A (car Y)) (sublis A (cdr Y)) ) ) ) ) ) # And now we can make curry too! (de curri2 (Fun Args) (let (Par (pairlis2 (car Fun) Args) dropP '((X Y) (cond ((null Y) X) (T (dropP (cdr X) (cdr Y))) ) ) ) (list (dropP (car Fun) Args) (car (sublis Par (cdr Fun))) ) ) ) -> curri2 : (curri2 '((X Y) (+ X Y))) -> ((X Y) (+ X Y)) : ('((X Y) (+ X Y)) 1 2) -> 3 : (curri2 '((X Y) (+ X Y)) (1)) -> ((Y) (+ 1 Y)) : ('((Y) (+ 1 Y)) 2) -> 3 : (curri2 '((X Y) (+ X Y)) (1 2)) -> (NIL (+ 1 2)) : ('(NIL (+ 1 2))) -> 3
Re: binding free symbols in a lambda definition
Sorry for the large email and even while pretending to be a clarifying text it is not :( Also don't want to give an image of pretending to arrange picolisp's flaw design, it is absolutely not, not only I don't have the needed understanding of picolisp nor the knowledge to do so but I consider picolisp a pretty good design with very smart decisions. What I trying to do is speaking out loud spreading out my thoughts to see if my understanding is right and also to see if my ideas may be useful somehow or must be considered as nonsenses On Thu, Feb 9, 2017 at 2:17 AM, pdwrote: > > > But let me try to better explain myself... > >