Re: FEXPRs / PilCon
On Sun 14 Mar 2021 at 09:34, Alexis wrote: > My guess is that Tomas is using the latter meaning, and wants > 'pure' functions that simply return strings, without sending them > to an output device. The final string to be output would be > created by combining the return values of multiple functions, > possibly performing transformations on them along the way, then > sending _that_ string to an output device. Is that correct, Tomas? Pretty much, except instead of strings the values should be cons trees. Strings do not "compose" but cons trees do. Also with strings, the structure is lost but cons trees preserve the structure making it possible to know what exactly is being output and automatically escape accordingly. -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
On Sun, Mar 14, 2021 at 10:19 PM Alexander Burger wrote: > Hi pd, > > > They're are not intended to be right implementations, too bad for that > ;-) > > No no, I did not say that :) > :) ok but *I* say that, it's really not a code to show, only intended to show output > Right. The point is that FEXPRs allow you to write flow control in a way > not > possible with EXPRs. > exactly, > OK. But please don't mix up the issue with side effects. They have nothing > to do > with FEXPRs. > that's true, you can code for side-effects using fexprs or exprs. I simply said I prefer to code not using side-effects (even when sometimes are needed or the better solution) > > And in most cases you can get both (beauty and performance). > > touché! ;-) regards
Re: FEXPRs / PilCon
Hi pd, > > > : (de pp P (prin "") (run P) (prin "") (pack "" (run P) > > "") ) > > ... > > This is a bit problematic, because the body in P is executed twice. Not > > only is ... > >(de pp P > > (prin (pack "" (run P) "")) ) > yes, all my examples in my previous email are bad code, just for output > only, trying to offer examples of how things can go weird > They're are not intended to be right implementations, too bad for that ;-) No no, I did not say that :) I just wanted to show the obvious shortcut. > yes sure, I think the PilCon and this email thread are good examples of an > interesting use of fexprs but even complex and large programs may be > arranged in a way fexpr are not needed, it's a kind of condig style. Right. The point is that FEXPRs allow you to write flow control in a way not possible with EXPRs. > My point is you can do with fexprs everything you do with exprs but the > opposite is not true, fexprs have it own role in lisp. But I prefer to code > in a more functional style working composing functions with inmutable > objects and without side-effects. OK. But please don't mix up the issue with side effects. They have nothing to do with FEXPRs. > It's always a balance between performance and logical beauty (from my point > of view), but performance is not only about computing performarce but also > logic and conceptual performarce and even profiling or debugging > performance. And in most cases you can get both (beauty and performance). ☺/ A!ex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
On Sat, Mar 13, 2021 at 2:05 PM Alexander Burger wrote: > > Yes. (And strings are always immutable in PicoLisp anyway) > this is pretty interesting to be rembered, good for newbies to discover why it is that way ;-) > > : (de pp P (prin "") (run P) (prin "") (pack "" (run P) > "") ) > > This is a bit problematic, because the body in P is executed twice. Not > only is > this slower, but may create havoc because in a typical GUI program *all* > logic > happens in these bodies. This logic would be executed several times, doing > lots > of unexpecyed things. Better then: > >(de pp P > (prin (pack "" (run P) "")) ) > > yes, all my examples in my previous email are bad code, just for output only, trying to offer examples of how things can go weird They're are not intended to be right implementations, too bad for that ;-) > For such a simple example it works. But keep in mind that typically 'P' > is a large program, with lots of 'if's, 'while's and arbitrarily deeply > nested other HTML tags. > > yes sure, I think the PilCon and this email thread are good examples of an interesting use of fexprs but even complex and large programs may be arranged in a way fexpr are not needed, it's a kind of condig style. My point is you can do with fexprs everything you do with exprs but the opposite is not true, fexprs have it own role in lisp. But I prefer to code in a more functional style working composing functions with inmutable objects and without side-effects. It's always a balance between performance and logical beauty (from my point of view), but performance is not only about computing performarce but also logic and conceptual performarce and even profiling or debugging performance. At the end the smart decision is to choose the better tool for the job ;-) greets
Re: FEXPRs / PilCon
Alexander Burger writes: On Sat, Mar 13, 2021 at 06:48:22PM +0100, Tomas Hlavaty wrote: (de (Col . Prg) (prin "") (run Prg) (prin "") ) prin has side-effect. Nonsense! 'prin' *is* the only and desired effect. Mm, it seems to me that there might be a mutual misunderstanding here, due to two different meanings of 'side-effect'. The lay meaning of 'side-effect' is "an effect in addition to the one that was intended/desired". A technical meaning of 'side-effect', in functional programming, is "something which changes state": https://en.wikipedia.org/wiki/Side_effect_(computer_science) In this context, printing something to an output device changes global state; the 'state of the world' has been changed to one that includes the content output. My guess is that Tomas is using the latter meaning, and wants 'pure' functions that simply return strings, without sending them to an output device. The final string to be output would be created by combining the return values of multiple functions, possibly performing transformations on them along the way, then sending _that_ string to an output device. Is that correct, Tomas? Alexis. -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
On Sat 13 Mar 2021 at 21:13, Alexander Burger wrote: > On Sat, Mar 13, 2021 at 08:59:37PM +0100, Tomas Hlavaty wrote: >> On Sat 13 Mar 2021 at 19:09, Alexander Burger wrote: >> > On Sat, Mar 13, 2021 at 06:48:22PM +0100, Tomas Hlavaty wrote: >> >>(de (Col . Prg) >> >> (prin "") >> >> (run Prg) >> >> (prin "") ) >> >> >> >> prin has side-effect. >> > >> > Nonsense! 'prin' *is* the only and desired effect. >> >> see https://en.wikipedia.org/wiki/Side_effect_(computer_science) >> for explanation what side-effect means > > I think I know what a side effect is ... > > But OK, "In computer science, an operation, function or expression is said to > have a side effect if it modifies some state variable value(s) outside its > local > environment". > > Please where does have a side effect? prin performs I/O calls prin Example side effects include [...] performing I/O or calling other side-effect functions. > Again: This discussion is Kindergarten. I wonderhow many members of this list > we > drive off. hmm > Haha, come on! Don't be picky! In this case 'Cls' is a simple class name. > Garbage in garbage out. Similar attitude have developers of beA - Das besondere elektronische Anwaltspostfach - BRAK. They do not escape their XML properly but use string concatenations. The result is that their XML responses are invalid and I cannot use proper validating XML parser but have to extract relevant data ad-hoc using text search. And using this software is mandated by German law! I would not be surprised if the whole thing is totally insecure. Goodbye mandant/lawyer confidentiality. -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
On Sat 13 Mar 2021 at 19:09, Alexander Burger wrote: > On Sat, Mar 13, 2021 at 06:48:22PM +0100, Tomas Hlavaty wrote: >>(de (Col . Prg) >> (prin "") >> (run Prg) >> (prin "") ) >> >> prin has side-effect. > > Nonsense! 'prin' *is* the only and desired effect. see https://en.wikipedia.org/wiki/Side_effect_(computer_science) for explanation what side-effect means >> Col is not properly escaped! > > How so? It generates > > > > What kind if escape do you want? ( "\">") -> "> which is invalid html. >> So will I see the generated html in stderr? > > Sigh! Please think a little. I said the output goes to the current stream and > debug info to stderr. Good old Unix style. Exactly, so debug info will not show me the generated html which means trace does not show me what I need. Trace is useful for pure functions. Trace is less useful for functions with side-effects because those side-effects are not captured by trace. -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
On Sat 13 Mar 2021 at 18:48, Tomas Hlavaty wrote: > would be better written as: > >(de p @ (cons 'p (args))) s/args/rest: (de p @ (cons 'p (rest))) -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
On Sat 13 Mar 2021 at 19:09, Alexander Burger wrote: > On Sat, Mar 13, 2021 at 06:48:22PM +0100, Tomas Hlavaty wrote: >>(de (Col . Prg) >> (prin "") >> (run Prg) >> (prin "") ) >> >> prin has side-effect. > > Nonsense! 'prin' *is* the only and desired effect. see https://en.wikipedia.org/wiki/Side_effect_(computer_science) for explanation what side-effect means >> Col is not properly escaped! > > How so? It generates > > > > What kind if escape do you want? ( "\">") -> "> which is invalid html. >> So will I see the generated html in stderr? > > Sigh! Please think a little. I said the output goes to the current stream and > debug info to stderr. Good old Unix style. Exactly, so debug info will not show me the generated html which means trace does not show me what I need. Trace is useful for pure functions. Trace is less useful for functions with side-effects because those side-effects are not captured by trace. -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
On Sat, Mar 13, 2021 at 07:09:24PM +0100, Alexander Burger wrote: > > prin has side-effect. > > Nonsense! 'prin' *is* the only and desired effect. > ... > This discussion is useless. Now I think I understand why. Tomas misunderstood my initial mail. He did not attend PilCon, and seems to believe we discussed implementation strategies for libraries. This was not the case. I talked about binding mechanisms in FEXPRs. The two functions '' and '' are minimal printing abstractions. An expression like (prin "" "Text" "") can be abstracted as (de Prg (prin "") (run Prg) (prin "") ) ( (prin "Text")) and this was used then in nested calls to demonstrate the behavior of 'Prg's. In a digression, the question about 'pack'ing strings came up, and I felt I had not fully answered the question, so I clarified it in the above mail. ☺/ A!ex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
On Sat, Mar 13, 2021 at 06:48:22PM +0100, Tomas Hlavaty wrote: >(de (Col . Prg) > (prin "") > (run Prg) > (prin "") ) > > prin has side-effect. Nonsense! 'prin' *is* the only and desired effect. > Col is not properly escaped! How so? It generates What kind if escape do you want? > This example: > >(de Prg > (prin "") > (run Prg) > (prin "") ) > > These functions output the formatted html immediatelly, which is too > early for reasons I wrote about already. This is the last time I repeat: It is the PURPOSE! Nothing else is there which might be "too early". This discussion is useless. > So will I see the generated html in stderr? Sigh! Please think a little. I said the output goes to the current stream and debug info to stderr. Good old Unix style. -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
On Sat 13 Mar 2021 at 16:04, Alexander Burger wrote: > I don't get your problem with side effects! in your example: (de (Col . Prg) (prin "") (run Prg) (prin "") ) prin has side-effect. Col is not properly escaped! This example: (de Prg (prin "") (run Prg) (prin "") ) These functions output the formatted html immediatelly, which is too early for reasons I wrote about already. would be better written as: (de p @ (cons 'p (args))) This has no side-effects. It also allows me to postpone serialisation to a better point in time, when I call a function called html. Similar to xml function in picolisp, this html function serializes cons tree into a stream with html syntax. This way I never have to care about escaping and other issues. Separating p, div etc and html function opens new possibilities. > Why do you open new issues like like SVG and PDF generation, when the > task is to print a page to to a socket? Because cons trees can brilliantly represent pretty much anything, from lisp code to html, xml, svg, pdf, docx, odt, der, json etc. You can easily construct them, pretty-print them, trace them, transform them and serialize them. Picolisp way of implementing has fundamental flaws which the cons tree approach solves elegantly. >> > If you want output with a pre-calculated width, you can still do it in the >> > FEXPR. >> >> Not pre-calculated. The bounding box is known after the thing is drawn. > > That's trivial. Just calculate while printing then. That does not work, because with and height are not known yet at that time! They are known after the printing is finished, which is too late. >> If my code outputs html to /tmp/a.html and I trace it, where would the >> arguments and return values be written to? Where would the side-effect >> be written to? > > I already explained that tracing goes to stderr. So will I see the generated html in stderr? If yes then /tmp/a.html is empty and tracing breaks my program. If no then stderr will not contain the generated html and tracing is useless. -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
On Sat, Mar 13, 2021 at 04:04:56PM +0100, Alexander Burger wrote: > I don't get your problem with side effects! Anyway, we are completely off-topic now :) You started with critics about FEXPRs, but never said anything relevant about them. Your code examples like (de (Str) `(p ,Str)) are EXPRs. My example of (de printWidthAndPrint Prg (let ( pWidth divWidth prin length) (msg (run Prg)) ) (run Prg) ) is BTW a very good case demonstrating the power of FEXPRs combined with dynamic binding. ☺/ A!ex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
On Sat, Mar 13, 2021 at 03:33:23PM +0100, Tomas Hlavaty wrote: > On Sat 13 Mar 2021 at 15:03, Alexander Burger wrote: > I am talking about an example which shows how inconvenient the standard > picolisp your solution with side-effect is. > > Yet another example, writing out pdf. I don't get your problem with side effects! Why do you open new issues like like SVG and PDF generation, when the task is to print a page to to a socket? It was a minimal example for didactic purposes in PilCon. So what is the side effect? The printing??? Printing is all we are talking about here. And even besides this simple example, I want output of an HTML server as fast as possible, and the way the PicoLisp server does it is surely optimal. Both from the speed of page generation as also the simplicity of the HTML functions, and the readability of the source code (please show me a source code which generates a report in HTML in a cleaner way than the example of the Sales report in my last mail!). > Cons trees and garbage collection are one of the best things about lisp. Sure. But not an issue here! We want output, not a data structure. > > If you want output with a pre-calculated width, you can still do it in the > > FEXPR. > > Not pre-calculated. The bounding box is known after the thing is drawn. That's trivial. Just calculate while printing then. > So optimal means writing to a file is cheaper than consing a cell? I am > not convinced. We NEED the output, but we DON'T need the cell. > If my code outputs html to /tmp/a.html and I trace it, where would the > arguments and return values be written to? Where would the side-effect > be written to? I already explained that tracing goes to stderr. ☺/ A!ex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
On Sat 13 Mar 2021 at 15:03, Alexander Burger wrote: > On Sat, Mar 13, 2021 at 02:09:30PM +0100, Tomas Hlavaty wrote: >> Avoiding allocations is wrong thing to do for this use-case. Printing >> directly is severely inconvenient. Do you have a neat solution to the >> svg viewBox problem I wrote about? > > You are talking about a different problem domain. Width calculations > were not an issue in that discussion. I am talking about an example which shows how inconvenient the standard picolisp your solution with side-effect is. Yet another example, writing out pdf. https://logand.com/sw/emacs-pdf/file/emacs-pdf.el.html#l110 creates cons tree and implements insert-pdf function to serialize it in the right format. One of the issues here are pdf object references, which need to output "before" being known, making side-effect solution unuseable. Cons trees and garbage collection are one of the best things about lisp. Trading allocations for side-effects is a bad trade off. > If you want output with a pre-calculated width, you can still do it in the > FEXPR. Not pre-calculated. The bounding box is known after the thing is drawn. > But if you insist, just switch function pointers to do width > calculation instead of printing. Given our example > >(de Prg > (prin "") > (run Prg) > (prin "") ) > >(de (Col . Prg) > (prin "") > (run Prg) > (prin "") ) > > we add a width-calculating function for each tag: > >(de pWidth Prg > (+ 3 (run Prg) 4) ) > >(de divWidth (Col . Prg) > (+ 12 (length Col) 2 (run Prg) 6) ) Why separate and duplicate functions. What if the drawing is not so trivial? This is not a good solution. Generally, I want to update *W and *H during arbitrarily complex drawing without all those extra functions you suggest. > Note that this again does not produce a single cell. Optimal. So optimal means writing to a file is cheaper than consing a cell? I am not convinced. > I do not understand. We are talking about the 'trace' of function calls for > debugging, showing whe called function, and its arguments, then recursively > indented the trace of sub-function calls, and then the return of the function > and its value, right? Works fine with FEXPRs. > > 'trace' prints to stderr, so it does not interfer with other printing. If my code outputs html to /tmp/a.html and I trace it, where would the arguments and return values be written to? Where would the side-effect be written to? >> In reality it is misoptimisation because it optimizes for irrelevant >> advantage of no allocation but it severely criples what one can do. > > No. It cripples nothing. It is the most powerful concept. You can > express anything with it. I am not disputing that FEXPRs are the most powerful concept. I am saying that using it for html output is using wrong tool for the job. -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
On Sat, Mar 13, 2021 at 03:13:13PM +0100, Tomas Hlavaty wrote: > Another example: you have to be careful not to get an error in the > middle of the side-effect otherwise you get partial output. Hmm, sure, as in all kinds of programming. How does that relate to FEXPRs and/or tracing? Or do I misunderstand something? What do you mean with side-effect? The printing to the stream? ☺/ A!ex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
On Sat 13 Mar 2021 at 14:09, Tomas Hlavaty wrote: >> But the FEXPR solution explained at PilCon allocates no new cells at all. It >> prints directly. > > Avoiding allocations is wrong thing to do for this use-case. Printing > directly is severely inconvenient. Do you have a neat solution to the > svg viewBox problem I wrote about? Another example: you have to be careful not to get an error in the middle of the side-effect otherwise you get partial output. -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
On Sat, Mar 13, 2021 at 02:09:30PM +0100, Tomas Hlavaty wrote: > Avoiding allocations is wrong thing to do for this use-case. Printing > directly is severely inconvenient. Do you have a neat solution to the > svg viewBox problem I wrote about? You are talking about a different problem domain. Width calculations were not an issue in that discussion. If you want output with a pre-calculated width, you can still do it in the FEXPR. No need to build a separate "tree", the FEXPR body *is* one already. But if you insist, just switch function pointers to do width calculation instead of printing. Given our example (de Prg (prin "") (run Prg) (prin "") ) (de (Col . Prg) (prin "") (run Prg) (prin "") ) we add a width-calculating function for each tag: (de pWidth Prg (+ 3 (run Prg) 4) ) (de divWidth (Col . Prg) (+ 12 (length Col) 2 (run Prg) 6) ) For demonstration, say we want first print the width to stderr, and then the HTML to the current stream (de printWidthAndPrint Prg (let ( pWidth divWidth prin length) (msg (run Prg)) ) (run Prg) ) Test: (printWidthAndPrint ( "red" ( (prin "Text"))) ) Output: 34 Text Note that this again does not produce a single cell. Optimal. > > Also, needing two separate functions for every HTML function is ugly, > > tedious > > and error-prone. > > Not sure what do you mean. I meant '' and 'p' in your example. > > Side-effects like printing? No problem! In PicoLisp, you can trace, > > break and single-step FEXPRs (with or without side-effects) like any > > other function (unlike macros in e.g. Common Lisp). > > You can trace it but the trace does not show the side-effect thus making > trace useless. I do not understand. We are talking about the 'trace' of function calls for debugging, showing whe called function, and its arguments, then recursively indented the trace of sub-function calls, and then the return of the function and its value, right? Works fine with FEXPRs. 'trace' prints to stderr, so it does not interfer with other printing. > >> Using FEXPRs for html output is misoptimisation. > > > > Wrong. > > In reality it is misoptimisation because it optimizes for irrelevant > advantage of no allocation but it severely criples what one can do. No. It cripples nothing. It is the most powerful concept. You can express anything with it. You can see this from the fact that *all* primitives in the PicoLisp interpreter itself are FEXPRs (FSUBRs to be exact). ☺/ A!ex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
On Sat, Mar 13, 2021 at 01:57:58PM +0100, Alexander Burger wrote: > For such a simple example it works. But keep in mind that typically 'P' > is a large program, with lots of 'if's, 'while's and arbitrarily deeply > nested other HTML tags. For a short real-world example, take the "Sales" report from the PicoLisp Demo application (https://software-lab.de/demoApp.tgz). I include the source below. Functions like 'menu', '', 'form', '', 'csv', '', '' and '' are FEXPRs. The report runs through, generates the page, and gets garbage-collected. ☺/ A!ex # 08oct20 Software Lab. Alexander Burger (must "Sales" Report) (menu ,"Sales" ( NIL ,"Sales") (form NIL ( "-.-" ,"Date" NIL (prog (gui '(+Var +DateField) '*SalFrom 10) (prin " - ") (gui '(+Var +DateField) '*SalTill 10) ) ,"Customer" (choCuSu 0) (gui '(+Var +Obj +TextField) '*SalCus '(nm +CuSu) 30) ) (--) (gui '(+ShowButton) NIL '(csv ,"Sales" ( 'chart NIL ( (quote (align) (NIL ,"Date") (NIL ,"Customer") NIL (NIL ,"Zip") (NIL ,"City") (align ,"Total") ) ) (catch NIL (let Sum 0 (pilog (quote @Rng (cons *SalFrom (or *SalTill T)) @Cus *SalCus (select (@Ord) ((dat +Ord @Rng) (cus +Ord @Cus)) (range @Rng @Ord dat) (same @Cus @Ord cus) ) ) (with @Ord (let N (sum> This) ( (alternating) (<+> (: nr) This) (<+> (datStr (: dat)) This) (<+> (: cus nm) (: cus)) (<+> (: cus nm2)) (<+> (: cus plz)) (<+> (: cus ort)) (<-> (money N)) ) (inc 'Sum N) ) ) (at (0 . 1) (or (flush) (throw))) ) ( 'nil ( ,"Total") - - - - - ( (prin (money Sum))) ) ) ) ) ) ) ) ) -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
On Sat 13 Mar 2021 at 13:33, Alexander Burger wrote: > It does. Just the syntax is different: > >(de (@Str) (fill '(p @Str))) > > This also creates just 2 cells. True, I forgot about fill. > But the FEXPR solution explained at PilCon allocates no new cells at all. It > prints directly. Avoiding allocations is wrong thing to do for this use-case. Printing directly is severely inconvenient. Do you have a neat solution to the svg viewBox problem I wrote about? > Also, needing two separate functions for every HTML function is ugly, tedious > and error-prone. Not sure what do you mean. There would be only one function, lets call it html which takes a cons tree and prints it using html syntax. Opposite of tedious and error-prone. Similar to the xml function in picolisp. > Side-effects like printing? No problem! In PicoLisp, you can trace, > break and single-step FEXPRs (with or without side-effects) like any > other function (unlike macros in e.g. Common Lisp). You can trace it but the trace does not show the side-effect thus making trace useless. >> Using FEXPRs for html output is misoptimisation. > > Wrong. In reality it is misoptimisation because it optimizes for irrelevant advantage of no allocation but it severely criples what one can do. -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
On Sat, Mar 13, 2021 at 01:30:27PM +0100, pd wrote: > Composing strings (packing) have two main advantages: > > 1. Strings may be inmutable (you can return a new different string, maybe a > copy) > 2. Strings can be passed as parameter Yes. (And strings are always immutable in PicoLisp anyway) > : (setq X ( hallo)) > -> "" > : X > -> "" > > You can argue return value is nothing you must worry about because you're > only going to print the result, so better use it as a side effect. But this > is not always true, returning a string you can further compose it and make > transformations to it Right. The examples were for output only. > Ovbiously you can arrange the program (P) you pass to the fexpr and get > those problems solved by example packing into the result but it may become > not easy to write the function due to side effects: > > : (de pp P (prin "") (run P) (prin "") (pack "" (run P) "") ) This is a bit problematic, because the body in P is executed twice. Not only is this slower, but may create havoc because in a typical GUI program *all* logic happens in these bodies. This logic would be executed several times, doing lots of unexpecyed things. Better then: (de pp P (prin (pack "" (run P) "")) ) 'prin' returns the argument string. > the example given by Alex to get a multiline div is simply this one-liner: > > : (prinl (d "red" (glue "^J" (mapcar p '("ABC" "DEF" "GHI") > > ABC > DEF > GHI For such a simple example it works. But keep in mind that typically 'P' is a large program, with lots of 'if's, 'while's and arbitrarily deeply nested other HTML tags. ☺/ A!ex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
Hi Tomas, > > While this would surely work, I answered that it is a big overhead to > > generate the whole page as strings just to print them. > > Packing strings is not a good idea. Right. > It would be much better to create a cons tree instead, something like: > > (de (Str) `(p ,Str)) > > and have a separate function to print the cons tree into a stream > formatted as html. Notice how little memory such function allocates > -- 2 cons cells -- compared to the version with pack. > > Unfortunatelly, picolisp does not have a convenient way of creating cons > tree templates with backquote. It does. Just the syntax is different: (de (@Str) (fill '(p @Str))) This also creates just 2 cells. But the FEXPR solution explained at PilCon allocates no new cells at all. It prints directly. Also, needing two separate functions for every HTML function is ugly, tedious and error-prone. > > But I forgot to explain: The real reason for FEXPRs goes beyond that. They > > have > > the power of passing executable code bodies, with arbitrary flow control, > > to the > > function. > > This also nicely shows how the power of FEXPRs can easily lead one > astray. Right. FEXPRs are dangerous when used the wrong way. This was what the last PilCon was all about ("hazards"). But I explained also how these hazards disappear when you follow 2 or 3 simple rules in writing libraries. > Another drawback is that side-effects break tracing and make debugging > much harder. Side-effects like printing? No problem! In PicoLisp, you can trace, break and single-step FEXPRs (with or without side-effects) like any other function (unlike macros in e.g. Common Lisp). > Using FEXPRs for html output is misoptimisation. Wrong. ☺/ A!ex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
Re: FEXPRs / PilCon
That's true but with comments ;) Composing strings (packing) have two main advantages: 1. Strings may be inmutable (you can return a new different string, maybe a copy) 2. Strings can be passed as parameter The fexpr writing directly to stdout with print and running a program does not returns a string with the intended result: : (de P (prin "") (run P) (prin "")) -> : ( hallo) -> "" : (length ( hallo)) -> 4 : (setq X ( hallo)) -> "" : X -> "" You can argue return value is nothing you must worry about because you're only going to print the result, so better use it as a side effect. But this is not always true, returning a string you can further compose it and make transformations to it So first problem with this fexpr (programmed this way) you don't have the intended return value and thus you cannot use it as parameters to other function invocation Second problem is about inmutability, as you don't return the value you cannot have a completely different memory object. Ovbiously you can arrange the program (P) you pass to the fexpr and get those problems solved by example packing into the result but it may become not easy to write the function due to side effects: : (de pp P (prin "") (run P) (prin "") (pack "" (run P) "") ) : (pp (+ 2 3)) -> "5" : (pp 2) -> "2" : (pp (print 2)) 22-> "2" : (pp ( (prin "hallo"))) hallohallo-> "" : (pp (pp (prin "hallo"))) hallohallohallohallo-> "hallo" : ( ( (print "hallo"))) "hallo"-> "" so you must code carefully the fexpr, and anyway if you're going to return a string then side effects are often innecesary. More interesting is last use of fexpr which is the true reason of existence of fexpr's, being able to write macros But even when being needed as the only way to write certain functions (aka macros), most of the time are not needing, like the intended use with showed as an example by Alex. Given: : (de p (t) (pack "" t "")) : (de d (c t) (pack "" t "")) the example given by Alex to get a multiline div is simply this one-liner: : (prinl (d "red" (glue "^J" (mapcar p '("ABC" "DEF" "GHI") ABC DEF GHI El sáb., 13 mar. 2021 8:32, Alexander Burger escribió: > Hi all, > > at PilCon three days ago we discussed about FEXPRs like > >(de Prg > (prin "") > (run Prg) > (prin "") ) > >(de (Col . Prg) > (prin "") > (run Prg) > (prin "") ) > > which can be called as > >( "red" ( (prin "Text"))) > > giving such output: > >Text > > > One question that came up was why FEXPRs could not be replaced with normal > functions (EXPRs), simply 'pack'ing strings: > >(de (Str) > (pack "" Str "") ) > >(de (Col Str) > (pack > " Col > "\">" > Str > "" ) ) > >: ( "red" ( "Text")) >-> "Text" > > While this would surely work, I answered that it is a big overhead to > generate > the whole page as strings just to print them. > > > But I forgot to explain: The real reason for FEXPRs goes beyond that. They > have > the power of passing executable code bodies, with arbitrary flow control, > to the > function. > > To pick just a minimal example: > >( "red" > (for S '("ABC" "DEF" "GHI") > (prinl) > ( (prin S)) ) > (prinl) ) > > >ABC >DEF >GHI > > > This cannot be done with EXPRs. > > ☺/ A!ex > > -- > UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe > >
Re: FEXPRs / PilCon
On Sat 13 Mar 2021 at 08:27, Alexander Burger wrote: >(de Prg > (prin "") > (run Prg) > (prin "") ) > > [...] > > One question that came up was why FEXPRs could not be replaced with normal > functions (EXPRs), simply 'pack'ing strings: > >(de (Str) > (pack "" Str "") ) > > [...] > > While this would surely work, I answered that it is a big overhead to > generate the whole page as strings just to print them. Packing strings is not a good idea. It would be much better to create a cons tree instead, something like: (de (Str) `(p ,Str)) and have a separate function to print the cons tree into a stream formatted as html. Notice how little memory such function allocates -- 2 cons cells -- compared to the version with pack. Unfortunatelly, picolisp does not have a convenient way of creating cons tree templates with backquote. > But I forgot to explain: The real reason for FEXPRs goes beyond that. They > have > the power of passing executable code bodies, with arbitrary flow control, to > the > function. This also nicely shows how the power of FEXPRs can easily lead one astray. For example: (let (*X NIL *Y NIL) (draw-svg-thing-and-determine-width-and-height) `(svg (@viewBox "0 0 " ,*W " " ,*H) ...)) The above will not work when is not pure and does side-effect write. One has to draw it twice, once to /dev/null to determine width and height and then second time inside the three dots. When draw-svg-thing-and-determine-width-and-height is pure and returns cons tree, it does not need to be called second time but the return value can be used inside the three dots. If consing and garbage collecting a cons tree is cheaper than calling draw-svg-thing-and-determine-width-and-height once again, it is already a win. Another drawback is that side-effects break tracing and make debugging much harder. Using FEXPRs for html output is misoptimisation. -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe
FEXPRs / PilCon
Hi all, at PilCon three days ago we discussed about FEXPRs like (de Prg (prin "") (run Prg) (prin "") ) (de (Col . Prg) (prin "") (run Prg) (prin "") ) which can be called as ( "red" ( (prin "Text"))) giving such output: Text One question that came up was why FEXPRs could not be replaced with normal functions (EXPRs), simply 'pack'ing strings: (de (Str) (pack "" Str "") ) (de (Col Str) (pack "" Str "" ) ) : ( "red" ( "Text")) -> "Text" While this would surely work, I answered that it is a big overhead to generate the whole page as strings just to print them. But I forgot to explain: The real reason for FEXPRs goes beyond that. They have the power of passing executable code bodies, with arbitrary flow control, to the function. To pick just a minimal example: ( "red" (for S '("ABC" "DEF" "GHI") (prinl) ( (prin S)) ) (prinl) ) ABC DEF GHI This cannot be done with EXPRs. ☺/ A!ex -- UNSUBSCRIBE: mailto:picolisp@software-lab.de?subject=Unsubscribe