How to have the same output of puri:uri-parsed-path using the alternative library in Common Lisp called Quri? - uri

Using the CL (SBCL) and the Puri library, I get on Slime's REPL:
CL-USER> (puri:uri-parsed-path (puri:parse-uri "http://www.gnu.org/software/emacs/manual/html_node/emacs/index.html"))
(:ABSOLUTE "software" "emacs" "manual" "html_node" "emacs" "index.html")
I am trying to achieve the same output (a list with the split terms from the URL's path) using Quri instead of Puri.
Unfortunately, I am not achieving it. I have tried quri-parse-path:
CL-USER> quri-object
#<QURI.URI.HTTP:URI-HTTP http://www.gnu.org/software/emacs/>
CL-USER> (quri:parse-path (quri:uri-path quri-object))
"/software/emacs/"
0
16
Does the library already support this operation?
I am not sure it does only by reading the Quri's documentation. I am still a noob in CL, though.

I suggest getting the uri path, and splitting by "/":
(quri:uri "http://www.gnu.org/software/emacs/manual/html_node/emacs/index.html")
#<QURI.URI.HTTP:URI-HTTP http://www.gnu.org/software/emacs/manual/html_node/emacs/index.html>
(quri:uri-path *)
"/software/emacs/manual/html_node/emacs/index.html"
(ql:quickload "str")
(str:split "/" * :omit-nulls t)
("software" "emacs" "manual" "html_node" "emacs" "index.html")

Related

Reading qualified symbols

I'm working on a code formatter for Lisp, which is using the reader to read code into S-expression format.
This works fine for plain symbols.
It doesn't work so well for qualified symbols. foo:bar is only readable if the package foo has been defined, but of course as far as the formatter is concerned, it has not, because unlike the compiler, the formatter is only reading the code, not executing it.
How can I tell the reader to either go ahead and automatically create a package foo on the fly, or failing that, don't sweat it, just read foo:bar, not as a symbol per se, but in some unambiguous format I can deal with as a special case?
I believe that you should not use the reader for that, because that is lossy (you lose comments, and anything that gets changed through reader macros, e. g. read-time-values, read-time references etc.).
But if you want, you can automatically create the package and maybe also export the symbol by handling the error, e. g. on SBCL:
(handler-bind ((sb-int:simple-reader-package-error
(lambda (e)
(let ((p (sb-int::package-error-package e)))
(ctypecase p
(string
(make-package p)
(invoke-restart 'retry))
(package
(export (intern (first (simple-condition-format-arguments e)) p) p)
(invoke-restart 'retry)))))))
(with-simple-restart (retry "Retry")
(read-from-string "foo:bar")))
This is a bit hacky, and we have no guarantee that the format of the condition stays like that.

Bulk `unintern` for renamed exported symbols

I use packages a lot and the exported symbols often change their names. When I try to recompile the package I get warnings like this:
package.lisp:3:1:
warning:
MY-PROJECT also exports the following symbols:
(OLD-SYMBOL1 OLD-SYMBOL2 OLD-SYMBOL3)
See also:
Common Lisp Hyperspec, DEFPACKAGE [:macro]
SBCL Manual, *ON-PACKAGE-VARIANCE* [:variable]
--> EVAL-WHEN
==>
(SB-IMPL::%DEFPACKAGE "MY-PACKAGE" '("KE") 'NIL 'NIL 'NIL '("CL") 'NIL
'NIL '("NEW-EXPORTED-SYMBOL1" "NEW-EXPORTED-SYMBOL2") '("MY-PROJECT") 'NIL
...)
I know that I can use (unintern 'old-symbol1) to signal the system I don't want to use that symbol anymore. However this is becoming very tedious when there is a lot of renaming.
My questions are:
1) Is is possible to signal to sbcl or emacs to unintern the old/previously exported symbols automatically?
2) If not - is it possible to get all "old" symbols in a variable?
My plan for 2) is to make a key binding to something like (apply #'unintern *old-symbols*)
Setting the variable *on-package-variance* to a list (:error t) will give you an error instead of a warning when redefining the package. The error will have a restart DROP-THEM to unexport the symbols.
You can add
(setf *on-package-variance* '(:error t))
to your ~/.sbclrc to have it always set when starting up SBCL.
First I don't think you want to unitern symbols. Unintern removes them from the package. I think you want to unexport them to avoid the warning. You can do that with the following function
(defun unexport-package-symbols (package)
(do-symbols (symbol package)
(destructuring-bind (symbol status)
(find-symbol (symbol-name symbol) package)
(when (eq status :external)
(cl:unexport symbol package)))))
;; It takes a package-designator as an argument.
(unexport-package-symbols "MY-PACKAGE")

How to use console as input and output for Guile Scheme?

I understand that Scheme uses ports to perform Input and Output. While trying to learn how to get console input and output, I have come across MIT-Scheme's console-i/o-port variable.
But, the guile interpreter says it is an Unbound Variable. I would like to know how we can use ports to get input from and output to the console (Terminal in Unix) in a Guile Scheme Script. I am still a rookie in Scheme and Linux, a clear step-by-step is appreciated.
Also, how does (display <object>) work? Does it use ports inherently or is there another way.
P.S. If there is another way without using ports please let me know how to use that too.
If you want to read and write SExps, in guile you have (read), (write), (display) etc., if you want to read characters only use (read-char) and (write-char) -- they all use the input/output ports resp. you picked, by default they are stdin and stdout. Everything is rather straightforward (https://www.gnu.org/software/guile/manual/html_node/Input-and-Output.html#Input-and-Output).
You might also be interested in guile-ncurses (https://www.gnu.org/software/guile-ncurses/).
Of some more goodies check out pretty-print module from ice-9 (on very long sexps it's slow but outputs them really nicely formatted, great for e.g. code generation):
(use-modules (ice-9 pretty-print))
(pretty-print `(super cool stuff (+ 2 3) => ,(+ 2 3)))
And if you need your own parser, check out the lalr module (system base lalr).
edit a small example which reads a number, multiplies by itself and prints out the result:
#!/usr/bin/guile -s
!#
(let ((x (read)))
(display (* x x))
(newline))
(remember to chmod +x this script).
edit changed the expression to let form as Chris suggested, indeed the fewer parentheses the better
In guile you have 2 functions: current-input-port and current-output-port (the docs)
to read and put text into string (if you don't want to read s-expressions) you can use this function:
(define (read-port port)
(let iter ((result '()) (chr (read-char port)))
(if (eof-object? chr)
(list->string result)
(iter (append result (list chr)) (read-char port)))))
reading from stdin will be:
(read-port (current-input-port))
to write to stdout you can use display it also accept second argument which is port relevant docs

What's the meaning of "#+" in the code of cl-mysql? [duplicate]

This question already has answers here:
operator #+ and #- in .sbclrc
(2 answers)
Closed 6 years ago.
Recently I tried to read code about cl-mysql, but got stuck with the #+.
Tried to google it, but not work, so turn to here
(defun make-lock (name)
#+sb-thread (sb-thread:make-mutex :name name)
#+ecl (mp:make-lock :name name)
#+armedbear (ext:make-thread-lock)
#+ (and clisp mt) (mt:make-mutex :name name)
#+allegro (mp:make-process-lock :name name))
And looks like it is for different backend lisp compiler. But still no idea why write something like this.
Anyone can help me make it clear, thx.
#+ is a reader-macro that checks if a keyword is in the special variable *FEATURES*. If it isn't there, the following form will be skipped over (by the reader; the compiler will never see it). There is also #- which does the opposite.
There are some things that aren't part of the Common Lisp standard, but are important enough that all (or most) implementations provide a non-standard extension for them. When you want to use them in code that needs to work on multiple implementations, you have to use read-time conditionals to provide the correct code for the current implementation. Mutexes (and threads in general) are one of those things.
Of course there may be features provided by third party libraries as well. The contents of *FEATURES* will look something like this:
(:SWANK :QUICKLISP :SB-BSD-SOCKETS-ADDRINFO :ASDF-PACKAGE-SYSTEM :ASDF3.1
:ASDF3 :ASDF2 :ASDF :OS-UNIX :NON-BASE-CHARS-EXIST-P :ASDF-UNICODE :64-BIT
:64-BIT-REGISTERS :ALIEN-CALLBACKS :ANSI-CL :ASH-RIGHT-VOPS
:C-STACK-IS-CONTROL-STACK :COMMON-LISP :COMPARE-AND-SWAP-VOPS
:COMPLEX-FLOAT-VOPS :CYCLE-COUNTER :ELF :FLOAT-EQL-VOPS
:FP-AND-PC-STANDARD-SAVE :GENCGC :IEEE-FLOATING-POINT :INLINE-CONSTANTS
:INTEGER-EQL-VOP :INTERLEAVED-RAW-SLOTS :LARGEFILE :LINKAGE-TABLE :LINUX
:LITTLE-ENDIAN :MEMORY-BARRIER-VOPS :MULTIPLY-HIGH-VOPS :OS-PROVIDES-DLADDR
:OS-PROVIDES-DLOPEN :OS-PROVIDES-GETPROTOBY-R :OS-PROVIDES-POLL
:OS-PROVIDES-PUTWC :OS-PROVIDES-SUSECONDS-T :PACKAGE-LOCAL-NICKNAMES
:PRECISE-ARG-COUNT-ERROR :RAW-INSTANCE-INIT-VOPS :SB-DOC :SB-EVAL :SB-FUTEX
:SB-LDB :SB-PACKAGE-LOCKS :SB-SIMD-PACK :SB-SOURCE-LOCATIONS :SB-TEST
:SB-THREAD :SB-UNICODE :SBCL :STACK-ALLOCATABLE-CLOSURES
:STACK-ALLOCATABLE-FIXED-OBJECTS :STACK-ALLOCATABLE-LISTS
:STACK-ALLOCATABLE-VECTORS :STACK-GROWS-DOWNWARD-NOT-UPWARD :SYMBOL-INFO-VOPS
:UNIX :UNWIND-TO-FRAME-AND-CALL-VOP :X86-64)
So if you wanted to write code that depends on Quicklisp for example, you could use #+quicklisp. If you wanted code that is only run if Quicklisp is not available, you'd use #-quicklisp.
You can also use a boolean expression of features. For example,
#+(or sbcl ecl) (format t "Foo!")
would print Foo! on either SBCL or ECL.
#+(and sbcl quicklisp) (format t "Bar!")
would only print Bar! on SBCL that has Quicklisp available.
One could imagine that we can write:
(defun make-lock (name)
(cond ((member :sb-thread *features)
(sb-thread:make-mutex :name name))
((member :ecl *features*)
(mp:make-lock :name name))
...))
But that does usually not work, because we can't read symbols when their package is not existing and some packages are implementation/library/application specific. Packages are not created at read time in a lazy/automatic fashion.
In Common Lisp, reading a symbol of a package, which does not exist, leads to an error:
CL-USER 1 > (read-from-string "foo:bar")
Error: Reader cannot find package FOO.
1 (continue) Create the FOO package.
2 Use another package instead of FOO.
3 Try finding package FOO again.
4 (abort) Return to level 0.
5 Return to top loop level 0.
In your example sb-thread:make-mutex is a symbol which makes sense in SBCL, but not in Allegro CL. Additionally the package SB-THREAD does not exist in Allegro CL. Thus Allegro CL needs to be protected from reading it. In this case, the symbol sb-thread:make-mutex will only be read, if the the feature sb-thread is present on the cl:*features* list. Which is likely only for SBCL, or a Lisp which claims to have sb-threads available.
The feature expressions here prevents the Lisp from trying to read symbols with unknown packages - the packages are unknown, because the respective software is not loaded or not available.

lexical binding lost when switching package

All I wanted was to load an initialisation file for swank which wouldn't affect my lisp when it's started without swank...
I first tried #+swank (defun...) in my file that's loaded from ccl-init (trying this on ccl 1.10 + windows), and soon realised it's sourced before swank is loaded (obviously).
My aim is to define a simple function in :cl-user everytime I start swank. I just ended up with a swank add-hook to load my init.lisp file, and since I want to define the function in cl-user, I tried this in the init.lisp:
(let ((current-package *package*))
(in-package :cl-user)
(defun cd (dir)
(swank:set-default-directory
(parse-namestring dir)))
(in-package current-package))
Now, I don't recall if a defun in let was allowed, but lisp doesn't complain for it, but rather tells me that cur-pck symbol doesn't exist, and it seems when we switch the package, cur-pck binding gets out of scope. I thought cur-pck is a lexical binding, and that it should be reachable from within the lexical region, being independent from a package, am I wrong?
Why do I switch packages? I'm thinking that loading this file from swank at some initialisation point will define things in some swank package, that's why I wanted to try switching to cl-user first, define the function symbol, and switch back to let swank do it's thing.
At this point I guess I need someone to tell me I'm approaching the problem from the wrong angle, and that I should better choose an easier solution.
Additionally, out of curiosity in case above is the complete wrong approach, is there a way to define a symbol in another package within a function or a closure?
Switching packages in a form has no direct effect on the form
Let's look at this:
(in-package "FOO")
(let ((x 10))
(in-package "BAR")
(setf x 20))
Which x does it set to 20? FOO::X or BAR::X?
Well, it is FOO::X. Switching packages during execution has no effect on the symbols already read. The whole let form is read at once and the *package* value is used for that. Having an IN-PACKAGE in the form itself has no effect on the form itself.
Symbol with a package prefix
If you want to use a symbol in a certain package, just write the package prefix:
cl-user:foo ; if FOO is exported and the package exists
or
cl-user::foo ; if foo is not exported and the package exists
for example:
(defun cl-user::cd (...) ...)
Computing with symbols
You can also compute new symbols in packages you don't know yet:
(let ((sym-name "A-NEW-SYMBOL")
(my-package-name "SOME-EXISTING-PACKAGE"))
(intern sym-name my-package-name))
If the package does not exist, you can create it.
You can also set the function of a computed symbol:
(setf (symbol-function (compute-a-function-symbol))
#'(lambda ()
'foo))
If you want to define a function in a different package that the current one you can use a qualified symbol for a name
(defun cl-user::cd (dir)
(swank:set-default-directory
(parse-namestring dir)))
The binding is not being "lost". To test so yourself add (princ cur-pck) before the in-package form.
If you try evaluating (in-package *package*) you will see why your code fails to switch packages. The in-package macro does not evaluate its argument. The code that would give us the code we would want to evaluate is:
(let ((cur-pck *package*))
(in-package :cl-user)
(defun cd (dir)
(swank:set-default-directory
(1+ 2)))
(princ cur-pck)
`(in-package ,cur-pck))
However, as Rainer Joswig noted in his answer the in-package has no effect on forms already read, so it wouldn't work as desired even as a macro.
A style nitpick, don't use abbreviations, write current-package.
IN-PACKAGE is a macro, not a function. The problem in your code is that saying (in-package cur-pck) tries not to switch into the package denoted by the cur-pck variable but to the package named CUR-PCK (which obviously does not exist).
You can set the package temporarily with
(let ((*package* (find-package :cl-user)))
(defun cd (dir)
...))
But then again, the easiest way to achieve what you are doing would be
(defun cl-user::cd (dir)
...)
which totally eliminates the need to set the current package.

Resources