I got the following XML
<EXAMPLE>
<WANNAPRINT>
AWESOME
</WANNAPRINT>
<DONTWANNAPRINT>
BAD
</DONTWANNAPRINT>
</EXAMPLE>
I work with the given XML using CXML-STP and I only want to print the "wannaprint" section.
I am trying to achieve this using serialize:
(cxml-stp:serialize
(let ((last-step
(car
(cxml-stp:filter-children #'(lambda(node)
(and (typep node 'stp:element)
(string= (stp:local-name node)
"WANNAPRINT")))
(cxml-stp:first-child
(cxml:parse
"<EXAMPLE>
<WANNAPRINT>
AWESOME
</WANNAPRINT>
<DONTWANNAPRINT>
BAD
</DONTWANNAPRINT>
</EXAMPLE>" (stp:make-builder)))))))
(FORMAT t "last-step:~a~%" last-step)
last-step)
(cxml:make-string-sink))
But the result is simply "nil" and I do not understand why, as the printing of the "last-step" variable shows that the correct element has been selected.
How can I serialize/print an element of the cxml-stp:document into a string?
According to the documentation for cxml:make-string-sink, the string sinks return their strings as a result of a call to sax:end-document, so one thing you could do would be:
(let ((sink (cxml:make-string-sink)))
(cxml-stp:serialize
(let ((last-step
(car
(cxml-stp:filter-children #'(lambda(node)
(and (typep node 'stp:element)
(string= (stp:local-name node)
"WANNAPRINT")))
(cxml-stp:first-child
(cxml:parse
"<EXAMPLE> <WANNAPRINT> AWESOME </WANNAPRINT> <DONTWANNAPRINT> BAD </DONTWANNAPRINT> </EXAMPLE>"
(stp:make-builder)))))))
(FORMAT t "last-step:~a~%" last-step)
last-step)
sink)
(sax:end-document sink))
This seems a little icky, but there doesn't seem to be a mechanism exported to get at the ystream inside the sink.
Another way to do it would be to put your element (that is, last-step) in a document. I thought it would be as simple as (stp:make-document last-step) but it complains that the element already has a parent and I don't remember how to get around that right now. In any case, you might not want a document because its serialization includes the prelude (<?xml...?>).
Related
This question is somewhat related to an earlier one on programmatically generating symbol macros. I'm using that function in a convenience macro that throws undefined variable warnings. This macro and function:
(defmacro define-data (d body &optional doc)
(if (and doc (not (stringp doc))) (error "Documentation is not a string"))
`(let* ((d-str (string ',d))
(old-package *package*)
(*package* (if (find-package d-str) ;exists?
(find-package d-str) ;yes, return it
(make-package d-str)))) ;no, make it
;; Should we have an eval-when (:compile-toplevel) here?
(defparameter ,d ,body ,doc)
(export ',d old-package)
(define-column-names ,d)))
(defun define-column-names (d)
(maphash #'(lambda (key index)
(eval `(cl:define-symbol-macro ,key (cl:aref (columns ,d) ,index))))
(ordered-keys-table (slot-value d 'ordered-keys))))
are intended to be like defparameter, but additionally set up a few niceties for the user by defining:
a package with the name of d
a parameter in the current package with the data that will be sucked in by body
symbol-macros in package d for access to the individual data vectors
If I use defparameter from the REPL, and then call define-column-names, all is well. However when using the macro I get:
; in: DEFINE-COLUMN-NAMES FOO
; (DEFINE-COLUMN-NAMES CL-USER::FOO)
;
; caught WARNING:
; undefined variable: CL-USER::FOO
I suspect that this is because the compiler has no way of knowing that FOO will actually be defined when define-symbol-macro is called. Everything works fine, but I don't want the warning to frighten users, so am thinking of suppressing it. I hate suppressing warnings though, so thought I'd come here for a second opinion.
EDIT: I've marked an answer correct because it does correctly answer the question as asked. For an answer to the problem see my comments.
My answer to the 'when to muffle warnings' question in the title is: if it's your own code then never, under any circumstances. If it is someone else's code, then rewrite it not to warn unless you can't.
As to solving the problem I haven't thought about this hard enough, but the problem is that you definitely want the defparameter to be at top-level so the compiler can see it, and it can't really be if it's inside a let. But you can raise it to toplevel trivially since it depends on nothing inside the let.
I am then pretty certain that you want the rest of the macro to happen at compile time, because you definitely want the symbol-macros available at compile-time. So an attempt at the first macro would be (note I've fixed the handling of the docstring: (defparameter foo 1 nil) is bad):
(defmacro define-data (d body &optional doc)
(when (and doc (not (stringp doc)))
(error "Documentation is not a string"))
`(progn
(defparameter ,d ,body ,#(if doc (list doc) '()))
(eval-when (:compile-toplevel :load-toplevel :execute)
(let* ((d-str (string ',d))
(old-package *package*)
(*package* (if (find-package d-str) ;exists?
(find-package d-str) ;yes, return it
(make-package d-str)))) ;no, make it
(export ',d old-package)
(define-column-names ,d)))))
As a side note: although I think the fact that programmatically defining symbol macros is hard because CL left that out for some reason, I think I'd personally use some other approach rather than this, because eval is just so horrid. That's just me however: if you want to do this you do need eval I think (it is very rare that this is true!).
I am not sure exactly how define-columns-names works so I replaced it with a stub function that returns d.
Note also that you can use check-type and should try not injecting symbols in generated code, this introduces potential variable capture that can be avoided with gensym.
As far as I know you cannot use eval-when as suggested by your comment (see Issue EVAL-WHEN-NON-TOP-LEVEL Writeup for details).
But I have no warning if I declare the symbol as being special around the call.
(defmacro define-data (d body &optional doc)
(check-type doc (or null string))
(check-type d symbol)
(let ((d-str (string d)))
(alexandria:with-gensyms (old-package)
`(let* ((,old-package *package*)
(*package* (if (find-package ,d-str) ;exists?
(find-package ,d-str) ;yes, return it
(make-package ,d-str)))) ;no, make it
(defparameter ,d ,body ,doc)
(export ',d ,old-package)
(locally (declare (special ,d))
(define-column-names ,d))))))
It is also a bit strange that you expand into a call to define-column-names, which in turns evaluated a form built at runtime. I think it might be possible to do all you want during macroexpansion time, but as said earlier what you are trying to do is a bit unclear to me. What I have in mind is to replace define-column-names by:
,#(expand-column-names-macros d)
... where expand-column-names-macros builds a list of define-symbol-macro forms.
The other day (perhaps yesterday) I was quite perplexed about this #+nil read-time conditional found in https://github.com/billstclair/defperson/blob/master/defperson.lisp#L289.
After some deep thinking I came to the conclusion that this is very lispy way of commenting out code. Can someone confirm this?
Perhaps my assumptions are completely wrong. Anyway, thanks in advance.
Yes, it is a lispy way of commenting code, but you shouldn't leave this out in production code.
A better alternative is #+(or).
It only takes one more character, it takes the same key presses if you use Emacs paredit or some other mode that automatically inserts the closing parenthesis, and it's not subject to the existence of the symbol :nil in *features*.
See CLHS 2.4.8.17 Sharpsign Plus
To conditionalize reading expressions from input, Common Lisp uses feature expressions.
In this case it has been used to comment out a form.
It's a part of the reader. #+ looks if the next item, usually as a keyword symbol with the same name, is a member of the list *features*. If yes, the then next item is read as normal, if not, it is skipped.. Usually :NIL is not a member of that list, so the item is skipped. Thus it hides the expression from Lisp. There might have been a Lisp implementation, where this would not work : NIL, New Implementation of Lisp. It might have had the symbol :NIL on the *features* list, to indicate the name of the implementation.
Features like NIL are by default read in the keyword package:
#+NIL -> looks for :NIL in cl:*features*
#+CL:NIL -> looks for CL:NIL in cl:*features*
Example
(let ((string1 "#+nil foo bar")) ; string to read from
(print (read-from-string string1)) ; read from the string
(let ((*features* (cons :nil *features*))) ; add :NIL to *features*
(print (read-from-string string1))) ; read from the string
(values)) ; return no values
It prints:
BAR
FOO
Note that Common Lisp has other ways to comment out forms:
; (sin 3) should we use that?
#| (sin 3) should we use that?
(cos 3) or this? |#
I just discovered Racket a few days ago, and I'm trying to get more comfortable with it by writing a little script that generates images to represent source code using #lang slideshow.
I know that when programming in a functional paradigm it's good practice to create almost all your variables with let, but I find that it introduces too many levels of nesting and that Racket's let has an overcomplicated API which requires superfluous parentheses. I'm sure this is to remove ambiguity when using let in more powerful ways, but for my purposes it's just an annoyance. Consequently, I'm creating all my variables with define, and writing blocks with begin if I need to (such as in the body of an if statement).
The problem is that I've repeatedly been getting what seem to be very mysterious errors. I'm sure I'm just making some silly beginner's mistake, being new to the language, but I really can't seem to find the source of the complaint.
Here's the offending code:
(define sub-code (foldr ht-append (rectangle 0 0) (map internal-style (rest code))))
although what we're defining sub-code to seems pretty irrelevant. If I replace it with
(define sub-code '())
I receive the same error. DrRacket is saying that define is being used in an expression context. I understand what this error would normally mean - IE that it would raise when you write code like (print (define x 10)), but I can't see what would trigger it here.
If it helps, this define is at the beginning of a begin block, inside an if statement
(if (list? code)
(begin
(define sub-code '())
; a few more define statements and finally an expression ))
The specific error message DrRacket is printing is
define: not allowed in an expression context in: (define sub-code (quote ()))
I thought maybe define isn't allowed in begin blocks, but I checked the docs and one of the examples for begin is
(begin
(define x 10)
x)
So I don't really know what to do. Thanks in advance!
Definitions are allowed in a 'body' context, like in lambda and let among others. The consequent and alternate clauses of if are not body contexts; they are expression contexts and therefore definitions are not allowed.
begin is special - begin in a body context allows definitions, but begin in an expression contexts forbids definitions. Your case falls in to the later.
For example:
(define (foo . args) #| body context #|)
(define foo (lambda args #| body context |#))
(define (foo . args)
(let (...)
#| body context |#))
Syntactic keywords that requires expressions: if, cond, case, and, or, when, unless, do, begin. Check out the formal syntax in any Scheme report (r{4,5,6,7}rs); look for <body>, <sequence>, <command>, and <expression>.
Also, if you need a body context in an expression, just wrap a let syntactic form, as such:
(if test
(let ()
(define foo 'foo)
(list foo foo))
alternate)
As GoZoner explained, you can't use define in an expression context.
What could you do instead?
Use let:
(if (list? code)
(let ([x '()])
x)
...
Or it would work with an "empty" let and define:
(if (list? code)
(let ()
(define x '())
x)
...
But that's a bit silly.
Or use cond and define:
(cond [(list? code)
(define x '())
x]
...
This last way -- using cond and define -- is closest to what the current Racket style guide recommends.
Here's more details, from the Racket docs.
The different contexts are required because macros must expand differently, depending on which language forms are allowed.
As others have said, definitions are not allowed in expression contexts ("expr ..." in the docs), but are ok in other contexts.
In other doc entries, "body ..." indicates an internal-definition context (guide, reference), for example in lambda bodies, and "form ..." indicates all non-expression contexts, like in the docs for begin.
Or you could wrap the expressions in (begin)
e.g.(begin
(define x 10)
(define y 100)
(define z 1000))
I've been using noir in a web project and I came up to the point of restricting access to users, depending on their access level (and sublevel) to all possible routes defined by a defpage macro. So originally I had
(defpage [:post "/mysite"] {:as input}
(if-not (has-reqd-user-level? :levelX :sublevelY "/grantedRoute")
(noir.response/redirect "/insufficientRights")
...))
And then I thought this would get rid of boilerplate code:
(defmacro defpage-with-user-level [level sublevel granted-route route data expr]
`(defpage ~route ~data
(if-not (has-reqd-user-level? ~level ~sublevel ~granted-route)
(noir.response/redirect "/insufficientRights")
~expr)))
Finally, we use it as follows:
(defpage-with-user-level :levelX :sublevelY "/grantedRoute"
[:post "/mysite"] {:as input}
(html
[:body [:h1 (str "Hello " (:name input) "!")]]))
But as mentioned in this post made by Rich Hickey, https://groups.google.com/forum/#!msg/clojure/4II-HKr_Pu0/2IcKit99cagJ , it feels a little bit awkward because of positional binding, which is not idiomatic when there already exist maps.
However, I've been looking for some examples or discussions regarding the use of destructuring bindings in macros, and sadly, I hadn't found any clear use of them, because of its unevaluated expressions being passed through all along.
So, the following solution came to my mind:
(defmacro defpage-with-user-level [dts expr]
`(defpage (:route ~dts) (:data ~dts)
(if-not (has-reqd-user-level? (:level ~dts) (:sublevel ~dts) (:granted-route ~dts))
(noir.response/redirect "/insufficientRights")
~expr)))
But now, it's not clear how to pass the data map that maps locals from :get and :post into a local as in the examples above.
Am I doing right leaving my first attempt untampered or do I really need to use the second approach? I hope not. Is there any other option? Please, let me know.
Your first solution is fine. What Rich was talking about was using plain old maps to passing data around rather then creating new types/classes for each type of data. Ex: you can represnt a user information using a simple map rather than creating a class to represent user data.
As far as your second attempt is concerned, you can use map de-structuring in macro as:
(defmacro defpage-with-user-level [{:keys [route data level sublevel granted-route]} expr]
`(defpage ~route ~data
(if-not (has-reqd-user-level? ~level ~sublevel ~granted-route)
(noir.response/redirect "/insufficientRights")
~expr)))
(defpage-with-user-level {:level :levelX
:sublevel :sublevelY
:granted-route "/grantedRoute"
:route [:post "/mysite"]
:data {:as input}}
(html
[:body [:h1 (str "Hello " (:name input) "!")]]))
I'm new to Lisp and I was reading about an text-generator example in ANSI Common Lisp, Chapter 8. I follow the example and defined a function "see" in the scope of a LET variable "prec",
(let ((prec '|.|))
(defun see (symb)
(let ((pair (assoc symb (gethash prev *words*))))
(if (null pair)
(push (cons symb 1) (gethash prev *words*))
(incf (cdr pair))))
(setf prev symb)))
and saved it into a lisp file.
Then when I returned to REPL and tried to invoke see after loading the compiled version of the file, an error occurred:
The variable PREV is unbound.
[Condition of type UNBOUND-VARIABLE]
How do I invoke see properly? And what's a lexical closure for? I'm all confused.
Thanks for helping.
Looks like you've typed prec instead of prev in the enclosing let form.
Lexical closures are functions that 'close over' a part of the lexical environment (hence the name). There are many good introductions to closures in lisp that I will not attempt to repeat here but, essentially, let is the most common way to manipulate the lexical environment; in this case, you want to add the binding for prev, which will then be available to code within the body of the form. Your function see will 'close over' this binding, and so each call to see has access to it, even though when you make these calls, you will no longer be in the lexical environment established by the let form. You could say the function definition takes the binding with it, in a sense.
As you appear to have mis-typed the name of the prev, your function is trying to refer to a binding that has not been established at that point in the code.