This seemed like a use case for an or clause:
'[:find ?e1
:where (or [?e1 :a ?e2]
[?e1 :b ?e2]
[?e1 :c ?e2])
[?e2 :x "X"]]
But it fails with Unable to resolve symbol: ?e1 in this context.
Something like this should work
(let [rules '[(orclause ?e1 ?e2) [?e1 :a ?e2]
(orclause ?e1 ?e2) [?e1 :b ?e2]
(orclause ?e1 ?e2) [?e1 :c ?e2]]
dbval (d/db conn)]
(d/q '[:find ?e1
:in $ ?e2 %
:where (orclause ?e1 ?e2)]
dbval "X" rules))
Turns out I was just using an outdated version, or-clauses were introduced in 0.9.5130.
Related
In a new package I want to :use (inherit from) package packa and packb.
packa and packb have an intersection of exported symbols.
How is it possible to inherit all from packa but only those of packb that are not intersecting with packa?
UPDATE:
I've tried :use packa and selectively :import-from symbols from packb that I need and don't collide with packa. However that's quite combersome.
I've experimented a bit with do-external-symbols and intern/import, but that doesn't seem to work, or at least I don't know how it could work.
Shadowing is the way to avoid conflicts in this case.
If you want to use symbols from packa without a prefix, use :shadowing-import-from #:packa #:sym1 #:sym2 ... in your package definition. Or, use packb if you prefer those symbols without a prefix.
If you prefer to use prefixes for all of the conflicting symbols from both packages, use :shadow #:sym1 #:sym2 ... instead.
I assume that by 'an intersection of exported symbols' what you mean is that the two packages have an intersection of exported symbol names, not the symbols themselves (see below). So, for instance, I assume the packages are defined something like this:
(defpackage :p1
(:use)
(:export #:s1 #:s2))
(defpackage :p2
(:use)
(:export #:s2 #:s3))
Which means that both P1 and P2 export a symbol named "S2" but (eq 'p1:s2 'p2:s2) is false.
In this case you can't use both P1 and P2. You can massage things by explicitly importing (or shadowing-importing) symbols but generally that's quite undesirable, not to mention messy.
A good approach in this case is to define a conduit package, which is a package which simply acts as a conduit between you and one or more implementation packages, reexporting symbols as needed. The simplest approach is to use a pre-canned way of creating conduit packages such as Tim Bradshaw's 'conduit-packages' system, available in Quicklisp. (Some tentacle of ASDF also has a similar system I think but I am not familiar with that one.) This provides an extended variant of defpackage which does what you need.
Using this system, and with the above package definitions, you might say this to create a conduit:
(define-conduit-package :p3
(:use)
(:extends :p1)
(:extends/excluding :p2 #:s2))
This new package P3 now reexports the symbols from P1 and P2, except for P2:S2:
(use-package :p3)
t
> (symbol-package 's1)
#<The P1 package, 0/16 internal, 2/16 external>
> (symbol-package 's2)
#<The P1 package, 0/16 internal, 2/16 external>
> (symbol-package 's3)
#<The P2 package, 0/16 internal, 2/16 external>
You can obviously provide more than one symbol name to exclude, and you can pick and choose: assume you now have
(defpackage :p1
(:use)
(:export #:s1 #:s2 #:s3)
(defpackage :p2
(:use)
(:export #:s2 #:s3 #:s4))
(define-conduit-package :p3
(:use)
(:extends/excluding :p1 #:s3)
(:extends/excluding :p2 #:s2))
Then, this time without using P3 to make it easier to see:
> '(p3:s1 p3:s2 p3:s3 p3:s4)
(p1:s1 p1:s2 p2:s3 p2:s4)
You can also define conduits which extend packages only including certain symbol names, for instance:
(define-conduit-package :p4
(:use)
(:extends/including :p1 #:s1)
(:extends/excluding :p2 #:s1))
will tell it to reexport only the symbol named "S1" from P1, and not to reexport any symbol with this name from P2.
Finally you can of course define conduits with functions. For instance:
(defun make-conduit-package-excluding (n for-package/s excluding-from-package/s)
;; extend FOR-PACKAGE/S, excluding exports from EXCLUDING-FROM-PACKAGE/S
(let ((conduit (make-package n :use '()))
(excluders (if (listp excluding-from-package/s)
(mapcar #'find-package excluding-from-package/s)
(list (find-package excluding-from-package/s)))))
(dolist (p (if (listp for-package/s)
(mapcar #'find-package for-package/s)
(list (find-package for-package/s)))
conduit)
(do-external-symbols (s p)
(let ((sn (symbol-name s)))
(unless (some (lambda (excluder)
(multiple-value-bind (ss status) (find-symbol sn excluder)
(and (eq status ':external)
(not (eq ss s)))))
excluders)
(import s conduit)
(export s conduit)))))))
Now if I say (using the most recent definitions of P1 and P2 above:
> (make-conduit-package-excluding "P5" "P1" "P2")
#<The P5 package, 0/16 internal, 1/16 external>
> (use-package "P5")
t
> (use-package "P2")
t
Everything is again OK because I told the function that P5 should not reexport any symbols from P1 which would clash with P2's exports.
A note on 'intersection of exported symbols'. If you have two packages which export some of the same symbols rather than different symbols with the same names, then there is no issue using both. For example:
(defpackage :cl-re-1
(:use :cl)
(:export #:defpackage))
(defpackage :cl-re-2
(:use :cl)
(:export #:defpackage))
Then
> 'cl-re-1:defpackage
defpackage
> 'cl-re-2:defpackage
defpackage
> (use-package :cl-re-1)
t
> (use-package :cl-re-2)
t
If the problem is because you don't want to manually write down
all the overlapping functions - you could let a function write it down for you.
Let's say in a setting of:
(defpackage :p1
(:use :cl)
(:export #:s1 #:s2 #:s3))
(in-package :p1)
(defconstant s1 1)
(defconstant s2 2)
(defconstant s3 3)
(in-package :cl-user)
(defpackage :p2
(:use :cl)
(:export #:s2 #:s3 #:s4))
(in-package :p2)
(defconstant s2 "b")
(defconstant s3 "c")
(defconstant s4 "d")
(in-package :cl-user)
(defpackage :p3
(:use :cl :p1 :p2)
(:shadowing-import-from :p1 #:s2 #:s3)
(:export #:s1 #:s2 #:s3 #:4))
(in-package :p3)
;; package local nicknames
;; https://gist.github.com/phoe/2b63f33a2a4727a437403eceb7a6b4a3
(in-package :cl-user)
(defpackage :p4
(:use #:cl #:p1 #:p2)
(:shadowing-import-from #:p2 #:s2 #:s3)
(:export #:s1 #:s2 #:s3 #:s4))
(defpackage #:p5
(:use #:cl-user)
(:export #:s2 #:s3 #:s4))
I prefer to use uninterened keywords ("#:") to not to "pollute" the KEYWORD package's content.
One could then define the helper functions:
(defun make-uninterned-keyword (name)
"String to Uninterned Keyword"
(read-from-string (format nil "#:~a" name)))
(defun make-keyword (name)
"String to Keyword"
(values (intern (string-upcase name) "KEYWORD")))
(defun get-symbols (package)
"Return all symbols of a package
(`package` should be a string)"
(let (symbols)
(do-external-symbols (s (find-package (string-upcase package)))
(push s symbols))
(nreverse (mapcar #'symbol-name symbols))))
;; (lambda (s) (read-from-string (format nil "#:~a" (symbol-name s))))
(defun %overlapping-symbols (package-1 package-2)
"Determine symbols overlapping between the packages"
(let ((symbols-1 (get-symbols package-1))
(symbols-2 (get-symbols package-2)))
(intersection symbols-1 symbols-2 :test #'string=)))
(defun overlapping-symbols (package &rest packages)
"Determine symbols overlapping from first package with the rest of the packages"
(remove-duplicates (loop for pkg in packages
nconcing (%overlapping-symbols package pkg))
:test #'string=))
(defun generate-shadowing-import-form (package &rest packages)
"Construct code for shadowing-import-from"
(let* ((overlapping-symbols (apply #'overlapping-symbols package packages))
(overlapping-keywords (mapcar #'make-uninterned-keyword overlapping-symbols)))
`(:shadowing-import-from ,(make-uninterned-keyword package) ,#overlapping-keywords)))
(defun shadowing-import-string (package &rest packages)
"Construct string for :shadowing-import-from directive"
(string-downcase (format nil "~s" (apply #'generate-shadowing-import-form package packages))))
So by running:
(shadowing-import-string "P2" "P1" "P5")
;; => "(:shadowing-import-from #:p2 #:s2 #:s3 #:s4)"
You get the piece of code you want to copy paste into your
DEFPACKAGE definition. Any symbol in the :p2 package which overlaps with the :p1 and/or the :p5 package is then listed.
I made a small repro for this issue using only lisp.
file1.lisp :-
(defpackage :my_package
(:use :cl))
(in-package :my_package)
(defun subscribe (x) (print x)(terpri))
(export '(subscribe))
(in-package :cl-user)
file2.lisp :-
(defun loader ()
(load "file1.lisp")
(my_package:subscribe "hello"))
(loader)
Now, running this gives the same error :-
sbcl --load file2.lisp
This is SBCL 2.1.11.debian, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.
SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.
debugger invoked on a SB-C::INPUT-ERROR-IN-LOAD in thread
#<THREAD "main thread" RUNNING {1001834103}>:
READ error during LOAD:
Package MY_PACKAGE does not exist.
Line: 3, Column: 22, File-Position: 59
Stream: #<SB-INT:FORM-TRACKING-STREAM for "file /home/omkarwagh/swarajya/scratch/file2.lisp" {10009BF613}>
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT ] Abort loading file "/home/omkarwagh/swarajya/scratch/file2.lisp".
1: [CONTINUE] Ignore runtime option --load "file2.lisp".
2: Skip rest of --eval and --load options.
3: Skip to toplevel READ/EVAL/PRINT loop.
4: [EXIT ] Exit SBCL (calling #'EXIT, killing the process).
(SB-C:COMPILER-ERROR SB-C::INPUT-ERROR-IN-LOAD :CONDITION #<SB-INT:SIMPLE-READER-PACKAGE-ERROR "Package ~A does not exist." {10018375A3}> :STREAM #<SB-INT:FORM-TRACKING-STREAM for "file /home/omkarwagh/swarajya/scratch/file2.lisp" {10009BF613}>)
4
I guess that the problem is that we don't know the package at read time because the relevant file has not been loaded yet.
So the question is, what is the recommended practice in this case?
Original question
I have a roswell script that I've attached below. I have an asdf system called "my_system" which has only one module with one file that contains only one package called "my_package".
Somehow, the asdf system is being loaded but when I try to actually use any of the functions in it, then it fails with an error saying that "my_package" is not found
#!/bin/sh
#|-*- mode:lisp -*-|#
#|
exec ros -Q -- $0 $(readlink -f $(dirname $(readlink -f $0)))/asdf.conf "$#"
|#
(progn ;;init forms
(ros:ensure-asdf)
#+quicklisp(ql:quickload '() :silent t)
)
(defpackage :ros.script.test.3880638094
(:use :cl))
(in-package :ros.script.test.3880638094)
(require "asdf")
;(asdf:load-system "my_system")
;(print #'my_package:subscribe)
(defun main (mydir &rest argv)
(declare (ignorable argv))
(asdf:initialize-source-registry `(:source-registry :inherit-configuration (:include ,mydir)))
(asdf:load-system "my_system")
(sleep 0.2)
(print "here3")(terpri)
(print (list-all-packages))
(do-external-symbols (s (find-package :my_package)) (print s))
(print #'my_package::subscribe)(terpri)
)
;;; vim: set ft=lisp lisp:
The error is :-
Unhandled SB-C::INPUT-ERROR-IN-LOAD in thread #<SB-THREAD:THREAD "main thread" RUNNING
{1004460113}>:
READ error during LOAD:
Package MY_PACKAGE does not exist.
However, if I comment out this line :-
(print #'my_package::subscribe)(terpri)
I do in fact, see the package in the list of packages as well as the symbol in question :-
#<PACKAGE "MY_PACKAGE">
MY_PACKAGE:SUBSCRIBE
As you said, the error is signalled because the package does not exist at the read time (when the form is read as text and translated to symbols).
The most straightforward option to change the code above this is to create the symbol when function is executed, e.g., (funcall (intern "SUBSCRIBE" 'my-package)). Variant of this (using read-from-string instead of intern) can be seen in the Swank or Slynk loader.
If you use asdf (which is implied in your question), you should probably use uiop to do this for you - see uiop:symbol-call. For example, documented way to define test-op is with
:perform (test-op (o c) (symbol-call :fiveam '#:run! :foobar)))
However, most libraries structure files in such a way that this issue does not arise - the file1.lisp would be loaded before file2.lisp (e.g., using asdf system definition).
When trying to require the following macro in another file, the raise seems to be triggering immediately:
(defmacro assert [a [b True] [message None]]
`(unless (= ~a ~b) (raise (AssertionError (or ~message ~a)))))
This results in an AssertionError: True.
Steps to reproduce (sometimes works, and sometimes doesn't):
echo '(defmacro assert [a [b True] [message None]] `(unless (= ~a ~b) (raise (AssertionError (or ~message ~a)))))' > a.hy
echo '(require a [assert])' > b.hy
echo '(assert True)' >> b.hy
hy b.hy
In another instance of Python evaluating function arguments before names, as stated by Kodiologist in their comment here and their answer on one of my previous questions "Non-existent hy macros runs assertions, but fails appropriately with everything else", the issue was that unless didn't trigger a NameError when it didn't exist, since it was moved from the hy core to hyrule a little over a year ago.
With the following (simplified) code:
(setv agnostic-manager-installers {})
(defmacro alias-assign [am &rest aliases]
(for [alias aliases] (assoc
agnostic-manager-installers
(str alias)
(-> (globals) (get (str am)) (get "install")))))
(setv brew {
"prefix" "/home/linuxbrew/.linuxbrew/"
"install" (defn brew [] (run
"curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh | sudo bash"
:shell True))
})
(alias-assign brew brew homebrew home-brew linuxbrew linux-brew)
I'm getting the following error:
Traceback (most recent call last):
File "/home/shadowrylander/.local/syvl/python/hy/bin/hy", line 8, in <module>
sys.exit(hy_main())
File "/usr/lib/python3.9/contextlib.py", line 137, in __exit__
self.gen.throw(typ, value, traceback)
File "<stdin>", line 9, in alias_assign
hy.errors.HyMacroExpansionError:
File "<stdin>", line 20
(alias-assign brew brew homebrew home-brew linuxbrew linux-brew)
^--------------------------------------------------------------^
expanding macro alias-assign
KeyError: 'brew'
I thought the macro was not supposed to evaluate the arguments until compile-time, if I'm reading the error correctly (which I don't think I am)? Basically, I would like to not write the double quotes around every single alias provided to alias-assign, which is why I went with a macro.
Here's some much simpler code that produces the same error:
(setv brew 1)
(defmacro m []
(get (globals) "brew"))
(m)
Perhaps the problem is more obvious now: trying to access the global variable brew during macro-expansion doesn't work because brew doesn't exist during compile-time, when macro-expansion happens. The same problem occurs, with NameError instead of KeyError, if you just say brew instead of (get (globals) "brew"). In any case, the form (setv brew 1) won't be evaluated until run-time. One way around this is to say (eval-when-compile (setv brew 1)) instead. This makes the evaluation happen earlier.
A broader problem is that you seem to be executing code that you actually want to return, as the result of the macro expansion. After all, the body of your macro is a for, so it will always return None. Contrast with the following code, which uses quoting and unquoting to generate forms and return them (and uses updated syntax):
(setv agnostic-manager-installers {})
(defmacro alias-assign [am #* aliases]
`(do ~#(gfor
alias aliases
`(setv (get agnostic-manager-installers ~(str alias))
(get ~am "install")))))
(setv brew (dict
:prefix "/home/linuxbrew/.linuxbrew/"
:install "placeholder"))
(alias-assign brew brew homebrew home-brew linuxbrew linux-brew)
(print (hy.repr agnostic-manager-installers))
The result is:
{"brew" "placeholder" "homebrew" "placeholder" "home-brew" "placeholder" "linuxbrew" "placeholder" "linux-brew" "placeholder"}
I'm trying to create a binding to libpython using scheme's FFI. To do this, I have to get the location of python, create the ffi-lib, and then create functions from it. So for instance I could do this:
(module pyscheme scheme
(require foreign)
(unsafe!)
(define (link-python [lib "/usr/lib/libpython2.6.so"])
(ffi-lib lib))
This is all well and good, but I can't think of a way to export functions. For instance, I could do something like this:
(define Py_Initialize (get-ffi-obj "Py_Initialize" libpython (_fun -> _void)))
...but then I'd have to store a reference to libpython (created by link-python) globally somehow. Is there any way to export these functions once link-python is called? In other words, I'd like someone using the module to be able to do this:
(require pyscheme)
(link-python)
(Py_Initialize)
...or this:
(require pyscheme)
(link-python "/weird/location/for/libpython.so")
(Py_Initialize)
...but have this give an error:
(require pyscheme)
(Py_Initialize)
How can I do this?
Probably the easiest way to do something like this is to delay the binding until they're needed. Something like this (untested) code:
#lang scheme
(require scheme/foreign)
(unsafe!)
(define libpython #f)
(define (link-python [lib "/usr/lib/libpython2.6.so"])
(if libpython
(error "Foo!")
(begin (set! libpython (ffi-lib lib))
(set! Py_Initialize
(get-ffi-obj "Py_Initialize" libpython
(_fun -> _void))))))
(define (Py_Initialize . args)
(error 'Py_Initialize "python not linked yet"))
Ir you can do the setting inside the function itself, so you don't bind functions that are never called:
#lang scheme
(require scheme/foreign)
(unsafe!)
(define libpython #f)
(define (link-python [lib "/usr/lib/libpython2.6.so"])
(if libpython (error "Foo!") (set! libpython (ffi-lib lib))))
(define (Py_Initialize . args)
(if libpython
(begin (set! Py_Initialize
(get-ffi-obj "Py_Initialize" libpython
(_fun -> _void)))
(apply Py_Initialize args))
(error 'Py_Initialize "python not linked yet")))
and since you won't want to do this for every single function, you should wrap it in a macro:
#lang scheme
(require scheme/foreign)
(unsafe!)
(define libpython #f)
(define (link-python [lib "/usr/lib/libpython2.6.so"])
(if libpython (error "Foo!") (set! libpython (ffi-lib lib))))
(define-syntax-rule (defpython <name> type)
(define (<name> . args)
(if libpython
(begin (set! <name> (get-ffi-obj '<name> libpython <type>))
(apply <name> args))
(error '<name> "python not linked yet"))))
(defpython Py_Initialize (_fun -> _void))
(defpython Py_Foo (_fun _int _int -> _whatever))
...more...
But two highlevel notes:
Even though it's possible, it seems ugly to delay things this way. I'd rather use some environment variable that is known when the code starts.
There have been an attempt in the past to link plt scheme to python, and IIRC, dealing with memory issues was not pleasant. (But this is before we had the current foreign system in place.)
I have not made many modules, but I think you need to 'provide' the functions that you want to load into the new namespace.
(module pyscheme scheme
(provide
link-python
Py_Initialize
<...>)
(require foreign)
(unsafe!)
(define (link-python [lib "/usr/lib/libpython2.6.so"])
(ffi-lib lib)))
(require pyscheme)
(link-python "/weird/location/for/libpython.so")
(Py_Initialize)
CMake can automatically find libpython path:
find_package( PythonLibs 3.3 REQUIRED )
More detailed example here.
Then you can use some linked sherd lib.
For example:
https://github.com/niitsuma/pyjsonrpcembd