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 - rrq

#31
If that printing happens from a CGI script for newlisp in -html operation, then it'd be explained as an API misunderstanding. newlisp in -html mode is quite forgiving about the CGI response, but it treats anything before the first empty line as the HTTP headers part, and that following the first empty line to be the HTTP payload part. That division holds regardless of whether the HTTP headers part is syntactically correct or not, where it silently discards anything non-header-ish. I remember it all as nicely documented but I can't bother looking it up right now.



Thus, if that's the reason, you would revise the template printing to add an initial newline
(println "n" template)  to serve the template text in full as HTTP payload.
#32
The use of  single symbol is not a documented http://www.newlisp.org/downloads/newlisp_manual.html#let">syntax form, and generally, that second element of the let term is not evaluated but processed as is (and only evaluated in parts). So that syntax form is a DIY opportunity :)



For a once-off need, I'd wrap it into a letex, as in the following.
(letex (l l) (let l (+ a b))) and for a more regular need, I'd define me a macro like the following:
(define-macro (lett)
    (if (list? (args 0)) (apply let (args))
        (apply let (cons (eval (pop (args))) (args))) ))

The latter would be a new function lett that kind of extends the function of let, but also lets me have a symbol as second element, in which case that symbol is evaluated so as to obtain an actual second argument for the let term. Thus, for your example, you would use (lett l (+ a b))

However, the resulting syntax is a case of non-local variable references (since the lett body includes a and b as out of context references), and that is something I would generally try to avoid, as I find it rather lacking in clarity, More specifically, the passing in of a variable assignment list into a let form conflates meta level and object level logic for no obvious reason, since the passed in list has to include the particular assignments that the body of the let form expects/requires anyhow, to be of any use. So if this would be used in a program, then that program would be slightly harder to read and understand than the equivalent program without using this feature.
#33
If you read first argument to format very carefully a few times, you will eventually discover the missing back-quote. :)
#34
Yes, I kind of thought that jsondata was the whole thing. Since you have
(set 'jsondata (lookup "products" (lookup "result" alie))) it'll already have gone into the "products" value part, and therefore my suggested ref of a ("product" ?) pair in jsondata isn't much good. As you noticed :)



If jsondata holds that value part of "products", then you'd get the simpler map term of: (map raisins jsondata) . And, completed with a println it might look like: (println (join (map raisins jsondata) "n"))
The key in my suggestion is that the term form, with different x and y:(if (ref '(x ?) y match true) ($it 1) '()) picks and returns the value part, i.e. the second element, of the first sub list of y starting with x at any depth in a depth-first traversal. It's a quick way to find stuff especially in a json structure, where one often will want to ignore the actual nesting of sub lists and just focus on the details of interest; the raisins in the cake :)



To be clear, the embedding into an if term: (if R ($it 1) '()) serves the purpose of avoiding a bad error if the ref term (i.e. the R above) doesn't find anything, and returns nil. In that way the code avoids the attempt of getting the value part of a list that isn't there (although it would be there had the ref succeeded). That embedding also utilizes the $it feature of newlisp, which simply holds the value of the condition term (it's available in if and and terms).
#35
You may want to build around using ref and ref-all, to "pick raisins";  something like this perhaps:
(define (raisins jsonitem)
    (format "<a href="%s">%s</a>n"<img src="%s">nn"
          (string (if (ref '("productUrl" ?) jsonitem match true) ($it 1)))
          (string (if (ref '("imageTitle" ?) jsonitem match true) ($it 1)))
          (string (if (ref '("imageUrl" ?) jsonitem match true) ($it 1))) ))

(map raisins (if (ref '("producs" ?) jsondata match true) ($it 1) '())


hth
#36
I suppose it links back to how the case term works in other Lisp variations.



There are also other conditional term forms such as if and cond to fill the need. Perhaps the prior question would be to ponder why having a case term at all.
#37
Yes, as you know, the case term does not evaluate the branch keys, so you'll have to resort to a letex embedding, as in
(define (f obj a da b db)
  (letex ((a a) (b b))
      (case obj
          (a da)
          (b db)
          (true obj)
   )))
#38
Indeed, sublist was a quite fun exercise. Thanks :) I ended up with the following as my "best" candidate:
(define (sublists s (i 0) (n (inc (length s))) (N n))
  (collect (if (> n 2) (i (dec n) s) (> (setf n (dec N)) 2) ((inc i) (dec n) s))))
That one performed best for me, and (more or less incidentally) it lets you choose a later start point and a max length of the sub lists.



Implicit slice seemed to be ~10% faster than explicit slice, and the iterative collation was ~5 times faster than the recursive variant. I didn't try any imperative "push within double loop" variant as I would expect that to be even slower.
#39
Thanks. Yes, as you say, the trans function really treats its input list s as a collection of equivalence classes, and combines those that overlap into the smallest collection of classes.



The similar function for non-reflexive relations (or directed arcs) would rather concern transitive reachability, from one element to those that are reachable when following the articulated relation (links) in the forward direction only. I came up with the following for that, which is two functions: one that determines the individual reach from a given element, and an outer function that makes the map of all those for all the elements:
(define (reach s n (f (fn (x) (= n (x 0)))))
  (cons n (if s (flat (map (curry reach (clean f s))
                           (map (curry nth 1) (filter f s)))))))

(define (reachability s)
  (map (fn (x) (reach s x)) (sort (unique (flat s)))))

> (reachability '((13 1) (9 19) (4 13) (4 12) (15 8) (3 15) (7 5) (9 4) (11 0) (0 5)))
((0 5) (1) (3 15 8) (4 13 1 12) (5) (7 5) (8)
 (9 19 4 13 1 12) (11 0 5) (12) (13  1) (15 8) (19))

(I added a line break for readability)



The "reachability map" in each sub list tells which elements are reachable from the first according to the original directed relation. So then it's a matter of inflating the map into pair-wise associations to make the directed transitive closure, e.g.:
(define (transD s)
  (flat (map (fn (x) (if (1 x) (map (curry list (x 0)) (1 x)) '())) (reachability s)) 1))

> (transD '((13 1) (9 19) (4 13) (4 12) (15 8) (3 15) (7 5) (9 4) (11 0) (0 5)))
((0 5) (3 15) (3 8) (4 13) (4 1) (4 12) (7 5) (9 19) (9 4) (9 13) (9 1) (9 12) (11  0) (11 5)  (13 1)  (15 8))
; i.e. the input plus implied reach: (3 8) (4 1) (9 13) (9 1) (9 12) (11 5)

Then, how do you go the other way? I.e. how do you reduce into the smallest number of pairs, or at least find a sub list so that implied relationships are omitted from the list?



newlisp is fun :)
#40
How about "transitive closure", then? I.e. given a list of pairs that notionally would, say, represent links in a graph, determine the lists of transitively connected "nodes", or in other words, join all sub-lists that share some element (transitively).



A recursive solution could be something like this:
(define (trans s (x s) (f (and s (curry intersect (first s)))))
  (if s (trans (rest s) (cons (unique (flat (filter f x))) (clean f x))) x))

> (trans '((13 1) (9 19) (4 13) (4 12) (15 8) (3 15) (7 5) (9 4) (11 0) (0 5)))
((7 5 0 11) (9 19 4 13 1 12) (15 8 3))

Perhaps there is something faster.
#41
I worked with that notion some while ago. In general it's possible to attach arbitrary data to an exe file, and thus generalize embedding into having multiple files, by overriding some file access functions to use that data where appropriate. In particular you would override load, file? and read-file to use attached data where possible.



This results in two script files: one for packing, and one being a special embedding script that takes care of using the attached data as the original files. For example as follows:



File: buildexe.lsp
# Requires arguments to be run as:
# newlisp buildexe.lsp lsp1 lsp2 .... binary

(constant 'ARGS (match '(?  "buildexe.lsp" * ?) (main-args)))
(constant 'HEAD "exehead.lsp")

(println "ARGS " ARGS)
(unless ARGS
  (write-line 2 "Run with: newlisp buildexe.lsp lsp1 lsp2 .... binary")
  (exit 1))

(unless (= (! (format "%s -x %s %s" (ARGS 0) HEAD (ARGS 2))))
  (write-line 2 (format "Failed to build %s" (ARGS 2))))

(append-file (ARGS 2) (dup "x" 50))
(dolist (f (ARGS 1))
  (let ((s (string (list 'EmbeddedFiles f (read-file f)))))
    (append-file (ARGS 2) (string (length s) s))))
(append-file (ARGS 2) " nil ")
(append-file (ARGS 2) (string (list 'load (ARGS 1 0))))
(exit 0)


File: exehead.lsp
(constant 'main_load load)
(constant 'main_read-file read-file)
(constant 'main_file? file?)

(define EmbeddedFiles:EmbeddedFiles nil)

(define (override_load _name)
  (if (EmbeddedFiles _name) (eval-string (EmbeddedFiles _name) MAIN)
    (main_load _name)))

(define (override_read-file _name)
  (if (EmbeddedFiles _name) (EmbeddedFiles _name)
    (main_read-file _name)))

(define (override_file? _name)
  (if (EmbeddedFiles _name) true (main_file? _name)))

(map constant '(load read-file file?)
     (list override_load override_read-file override_file?))

(define SELF:SELF (read-file (or (real-path (main-args 0))
                                 (real-path (string (main-args 0) ".exe")))))

(if (null? SELF)
    (exit (and (write-line 2 (format "No program %s" (main-args 0))) 1))
  (setf override_i (find (dup "x" 50) SELF))
  (let ((override_n 50))
    (while (number?
            (setf override_n
                  (read-expr SELF MAIN nil (inc override_i override_n))))
      (eval (read-expr SELF MAIN nil (inc override_i $count))))
    (eval-string SELF MAIN nil (inc override_i $count)))
  (exit (and (write-line 2 "No program") 1)))
(exit 0)


With those, you use buildexe.lsp for packing your other scripts, with the first being the main script, into a self-contained executable. In actual fact, the executable is simply a newlisp embedding of exehead.lsp with your script files as attached data that gets processed into the EmbeddedFiles hashtable. The filenames are the keys and the contents the values. The overriding functions try to find the given filename in the table first, for overriding, and otherwise fall back on the original functions.



hth
#42
Presumably the terminal control is done by writing control codes to stdout, and in that case you should rather use ! instead of exec. I.e.:
(! "cls")
(! "color 0b")

Alternatively at the interactive prompt, you can type the commands without parentheses and quoting by starting with the exclamation mark
> !cls
> !color 0b

The exec function runs a sub command and gathers its output lines into a list of strings, so to make this work with exec, you would need to print out those strings. Perhaps like this
(map println (exec "cls"))
(map println (exec "color 0b"))


Though, I don't use windows, so YMMV.
#43
mmm, did you check http://www.newlisp.org/downloads/newlisp_manual.html#define-macro">//http://www.newlisp.org/downloads/newlisp_manual.html#define-macro ?



The key point is that for m, its parameter lst gets bound to the un-evaluated argument '(+ 4 5), whereas in example 2 the eval function's parameter gets the evaluated argument (+ 4 5), i.e, without the single-quote. In other words, (m '(+ 4 5)) is actually the same as (eval ''(+ 4 5))
If you'd want an "m" function to be the same as an "eval" function, you'd use "define" rather than "define-macro". (Not totally the same, since "m" binds "lst" before calling "eval", but that's a separate concern)



hth
#44
RIght. And yet it's missing for newlisp.



Apparently Apache has "SetEnv" and "PassEnv" directives that possibly would service your use case. Or else, I suppose you can wrap the script with a shell script for this purpose. Or if you like living on the edge, you could apply a binary editor to your newlisp executable and put a 00 at the beginning of the boring output string ;)
#45
Hey!


Quote from: "dukester"
QuoteResponse header name 'Environment variable TMP not set, assuming /tmp .Content-Type' contains invalid characters, aborting request

That error message shows that newlisp has an initial "complaint" about "TMP", which means what it says, and that complaint precedes the script output. It has nothing to do with your script.



So the quest should rather be to get rid of that piece of output. That amounts to making sure that TMP is set before newlisp is invoked, or, you get it compiled without that complaint.