Sharing Lisp symbols across packages - common-lisp

I have a function foo defined in a package my-package:
(in-package :my-package)
(defun foo (a)
(if (eql a 'value1)
(do-this)
(do-the-other)))
When I call this function from a different package I have to qualify the parameter with the package name:
(in-package :cl-user)
(my-package:foo 'my-package::value1)
but this is rather ugly. I want to share the symbol value1 with all other packages.
I found one workaround which is to import the symbol value1, but this only works if it has been already defined in the other package.
Another possibility is to pass strings, "value1", but again, this is just a patch.
What is the best way to share symbols across packages?
Thanks for your help.

Use a keyword symbol, which you can always write without naming its package keyword:
(foo:bar :value1)
Keyword symbols are in the KEYWORD package, are evaluating to themselves, are automatically exported and you don't need to write down the package name.
Since a keyword symbol evaluates to itself, you even don't have to quote them - but you can.
(foo:bar ':value1)
Alternative: short package names
Sometimes it might be useful to have a symbol in a specific package. Then I would use a short package name, which you can also define as a nickname. See the options on DEFPACKAGE. For example the package color-graphics could have the nickname cg.
Then one would write:
(foo:bar 'cg:green)
Since it is a normal symbol, you have to quote it, otherwise it would be a variable.

Related

How does R access the package namespace without a call to library?

I was helping somebody with their code recently and they asked me why it was possible to use functions from a certain package (e.g. dplyr) without explicitly 'loading' (and attaching them) to the search path within R.
Specifically, why it is possible to write:
dplyr::mutate(...)
As opposed to:
library(dplyr)
mutate(...)
When you use ::, it doesn't appear to automatically 'attach' the functions from the namespace dplyr onto the search path. That only happens when you call library(). This confuses me slightly: when you use the :: approach, how does R find the function mutate() within dplyr without it being attached to the search path?
You may also consider making use of with. with is traditionally is used to undertake operations on the data but combined with asNamespace can be used to access functions from the packages without the need to load the package.
with(asNamespace("dplyr"),
select(mtcars, cyl) %>%
mutate(cyl_two = cyl * 2)
)
You can use :: and ::: to access a single function from a package, accounting for exported or not exported functions. If you look at the code of double and triple colon operators you will see that those leverage very similar mechanism. Package name is used to construct an environment via asNamespace and get1 function is used to source the function.
Broadly speaking, a potentially efficient way of thinking about that is comparing package functions to objects in an environment. By calling ::, ::: or with we can reference those objects.
1 In case of :: the actual function is getExportedValue.

Julia's equivalent to R's ?? (double question-mark help.search across all packages)

In R you can search the documentation by typing a question mark ? or a double question mark ??. How do you search the manual for strings in the Julia REPL?
>?first
No documentation for ‘first’ in specified packages and libraries:
you could try ‘??first’
>??first
In the R console a browser window opens up:
In RStudio the page is opened within the IDE.
The help() function and ? help operator in R provide access to the
documentation pages for R functions, data sets, and other objects,
both for packages in the standard R distribution and for contributed
packages.
The help() function and ? operator are useful only if you already know the name of the function that you wish to use. Other ways to search include apropos and ??
The apropos() function searches for objects, including functions,
directly accessible in the current R session that have names that
include a specified character string.
The ?? operator is a synonym for help.search(). The help.search()
function scans the documentation for packages installed in your
library. The argument to help.search() is a character string or regular expression.
P.S. I intend to answer my own question.
Julia has similar interactive utilties. Julia's main search utility for docstrings is named apropos.
To search the documentation for information about "first" in Julia, you have apropos("first") or equivalently ?"first". Thus ?"first" is roughly equivalent to R's ??.
To search for functions and methods, you can type a singe question mark ?, just as with R. In the Julia REPL, as you type the question mark, the prompt changes to a question mark. If you type "first" it searches through strings, while if you type first without quote-marks, you get a search over variables exported by the modules currently loaded.
Illustration:
help?>"first"
# or equivalently:
julia>apropos("first")
help?>first
If you search for a string, case is ignored. If you want to search within the DataFrames module, type using DataFrames before searching.
This also works in Visual Studio Code and Atom:

R package scope and masking

I think this is a simple question, and the answer is probably somewhere in either Hadley's book or the official R documentation, or in the answers to Writing robust R code: namespaces, masking and using the `::` operator, but I haven't come across it yet (or don't remember reading about it).
Let's say I want to write a package that contains the function:
sort_by_column <- function(x, j) {
j_ord <- order(x[, j])
x[j_ord, ]
}
If I define this function in the global environment and I pass in a value for x that is a data.table, it will silently fail because [ will dispatch to [.data.table instead of [.data.frame:
library(data.table)
sort_by_column(iris, 3)
sort_by_column(data.table(iris), 3)
My gut tells me that [.data.table won't even be available to my package unless I explicitly import it, in which case this problem can't occur in a package the way it can occur in the global environment. Is that true? If not, how can I handle this kind of masking?
edit 2: Function sort_by_column is defined in package A. Another package, B was loaded before package A but is not explictly imported by A. Do calls from functions defined in A search in package B?
edit: To clarify, I want to define a function inside a package in such a way that it "ignores" other packages the user might have loaded, in order to avoid function naming conflicts like the one demonstrated above. Is this ignoring behavior automatic, or do I need to do something in particular?
If you want to specify a particular method for "[" then you should be able to use:
`[.data.frame`(x, TRUE, j)
Or test for data.tables using inherits and trap that as an edge case?

Quicklisp: using loaded libraries

I've set up Quicklisp to run whenever SBCL runs, and added the following line to the top of my file that I'm trying to use the priority-queue library in (as suggested in the answer to my earlier question, Priority queue for Common Lisp?). However, when I try to use it, I get errors from SBCL, saying that the functions from priority-queue are not defined! What am I missing?
For reference, I tried to write something like this:
(ql:quickload "priority-queue")
(defparameter *heap* (make-pqueue #'<))
And I get an error saying that make-pqueue is not defined.
In common lisp, anything that's named (a variable, a function, a macro) is attached to a symbol. In this case, you have a function which is attached to the symbol make-pqueue. Symbols are separated from each other using packages. This keeps collisions to a minimum and also allows for things like internal variables/functions that aren't exported by the package.
Sounds like you need to do one of three things:
Use the package name before the function: (priority-queue:make-pqueue #'<). This method is good if you want people reading your source to know exactly what code is being run. however, it can get cumbersome if you call the package many times.
Use the priority-queue package in the current package you're in:
(use-package :priority-queue)
(make-pqueue #'<)
What this does is import every exported symbol from the priority-queue package into the current package you're in (most likely cl-user). While this is good for testing, you generally want to create your own package. See next item.
Define your own package that uses priority-queue:
(defpackage :queue-test (:use :cl :priority-queue))
(in-package :queue-test)
(make-pqueue #'<)
Defining your own packages seems like a lot of work at first, but you'll start to like the separation you get, especially if you start integrating different pieces of your code together.

How to get help in R?

What is the possible documentation available for R package? For example I try to understand sp package.
In addition to help(sp), what are the other functions for searching through help and documentation?
Getting help on a function that you know the name of
Use ? or, equivalently, help.
?mean
help(mean) # same
For non-standard names use quotes or backquotes; see An Introduction to R: Getting help with functions and features:
For a feature specified by special characters, the argument must be enclosed in double or single quotes, making it a “character string”: This is also necessary for a few words with syntactic meaning including if, for and function."
?`if`
?"if" # same
help("if") # same
There are also help pages for datasets, general topics and some packages.
?iris
?Syntax
?lubridate
Use the example function to see examples of how to use it.
example(paste)
example(`for`)
The demo function gives longer demonstrations of how to use a function.
demo() # all demos in loaded pkgs
demo(package = .packages(all.available = TRUE)) # all demos
demo(plotmath)
demo(graphics)
Finding a function that you don't know the name of
Use ?? or, equivalently, help.search.
??regression
help.search("regression")
Again, non-standard names and phrases need to be quoted.
??"logistic regression"
apropos finds functions and variables in the current session-space (but not in installed but not-loaded packages) that match a regular expression.
apropos("z$") # all fns ending with "z"
rseek.org is an R search engine with a Firefox plugin.
RSiteSearch searches several sites directly from R.
findFn in sos wraps RSiteSearch returning the results as a HTML table.
RSiteSearch("logistic regression")
library(sos)
findFn("logistic regression")
Finding packages
available.packages tells you all the packages that are available in the repositories that you set via setRepositories. installed.packages tells you all the packages that you have installed in all the libraries specified in .libPaths. library (without any arguments) is similar, returning the names and tag-line of installed packages.
View(available.packages())
View(installed.packages())
library()
.libPaths()
Similarly, data with no arguments tells you which datasets are available on your machine.
data()
search tells you which packages have been loaded.
search()
packageDescription shows you the contents of a package's DESCRIPTION file. Likewise news read the NEWS file.
packageDescription("utils")
news(package = "ggplot2")
Getting help on variables
ls lists the variables in an environment.
ls() # global environment
ls(all.names = TRUE) # including names beginning with '.'
ls("package:sp") # everything for the sp package
Most variables can be inspected using str or summary.
str(sleep)
summary(sleep)
ls.str is like a combination of ls and str.
ls.str()
ls.str("package:grDevices")
lsf.str("package:grDevices") # only functions
For large variables (particularly data frames), the head function is useful for displaying the first few rows.
head(sleep)
args shows you the arguments for a function.
args(read.csv)
General learning about R
The Info page is a very comprehensive set of links to free R resources.
Many topics in R are documented via vignettes, listed with browseVignettes.
browseVignettes()
vignette("intro_sp", package = "sp")
By combining vignette with edit, you can get its code chunks in an editor.
edit(vignette("intro_sp",package="sp"))
This answer already gives you a very comprehensive list.
I would add that findFn("some search terms") in package sos is extremely helpful, if you only have an idea/keywords of what you are looking for and don't already have a package or function in mind.
And also the task views on CRAN: not really a search process but a great place to wander as you wonder.
This thread contains many good suggestions. Let me add one more.
For finding which packages are loaded, plus extra goodies, ?sessionInfo is quite nice.
help(package="<package-name>") where of course <package-name> is the name of the package you want help for.
Often the same function name is used by several packages. To get help on a function from a specific package, use:
help(aggregate, package="stats")
help(aggregate, package="sp")
In the RStudio IDE you can click on any function name and press F1, which will directly open the associated function help text in its pane. Like you would have called help() or ?fun().

Resources