-
Notifications
You must be signed in to change notification settings - Fork 0
common lisp rosetta for the devs
A list of all CL language symbols. Note that 'some dude' wrote this stuff. Note that common lisp has too much in the spec and no standard libraries. Probably would have been better to separate the two.
Note that some of the features can be done with macros effectively. Still having thing possible, and having many people maintain versions of it separately is also annoying, it might still be handy to have a standard library.
Not really the same as Julia toplevel variables, in CL these are special variables;
(defvar *special* 1)
(print *special*) ; -> 1
(defun print-special () (print *special*))
(let ((*special* 2))
(print-special)) ; -> 2 local variable went right through to the function body.
(print-special) ; -> 1
Can be useful in having basically a 'context' that you do not have to keep passing and accessing a 'context object'. Could to better than the asterix convention to remind that the vars are special.
There is a bool
type in CL but anythint that is not nil
is true. This is useful; for instance (or a b c d)
returns the first non-nil one. Guessing this is shallow though, could easily make a macro in Julia returning
the first non-nothing
or non-false
one.
defun
is typically most used, there you can declare
types, but there is no overloading. defmethod
functions are overloaded. Common lisp forces you to make up your mind what the parameters of methods are in a defgeneric
form. Maybe they felt things are too 'wild' if there are lot of functions in different ways.
A function changing some particular thing can be made 'official', making it clearer what it does instantly.
(defun (setf something) (set-to ..args..)
...body setting it..
...probably should return set-to...)
(setf (something ..args..) set-to) ;Is how yo use it.
Of course it can be used alongside a non-setting version. Afaik, Julia doesn't have it,
setting stuff is done with =
, which isn't a function. (that can be overloaded) If this were to change one has to take into account that =
is used to define stuff in Julia aswel.
An idea is to implement something like this on 'accessors' and 'readers'; a.b
could run a function instead of accessing, but one that only depends on the object, and not changing any state.(just returning) (possibly excepting transparent memoizing) a.b = to
would run a function that assigns. (Well, much like assign
now, but with members instead.) Btw I do not like member functions used otherwise, i think Julia is wise to stay away from them.
Defines macros. Different with julia is that argument lists don't have to be flat for instance
(defmacro some-macro (a (b c) d) `(print ,a ,b ,c ,d))
(some-macro 1 (2 3) 4) ; -> (1 2 3 4)
(some-macro 1 2 3) ; -> macroexpansion-time error '2' should have been a list.
Defining macros seems a little trickier in some respects in Julia, and 'easier' in other respects. Making macros shouldn't be taken too lightly, usually you shouldn't.(where it is useful and mostly caveitless is usually either binding variables or defining stuff)
Probably more to say about the differences of representation of code in CL(just nested lists)
and Julia.(Probably mostly Expr
,QuoteNode
objects)
destructuring-bind
takes a list and similarly takes apart.(not seen it one Julia so far, can be done, though the 'rue analogy' would be called with-destructured-expr
or such)
compiler macros, define-compiler-macro
Adds a macro that will be called on a function call of that name. In Common Lisp these are
identical to macros but for two big differences; they can return nil
, and then the
implementation will ignore that the 'macro' ever ran and just keep the function. Or it can
return something else, and the code might be replaced if that something else is faster.(Probably you assume it is always faster and make
This sounds like something that may be nice to have. Caveit is that it is a full macro and could do anything, they have to be made pretty carefully. But it can probably exist alongside basically any other optimization stuff. But compiler macros just cover optimizing one little thing. If a general method can catch something-to-be-optimized, it should!
Local macro, the latter for just symbols. Not seen in Julia sofar, usual caveits of macros apply. I think not having it weakens macros a bit relative to those of CL.
case
basically a C switch
type macro, you give a value and each clause has a value or list
of values of which if any match, that clause is chosen. (It doesn't need to break;
every case
though, strange how C doesn't have a case
because not breaking seems so rare.)
typecase
is the same as case but instead of values, the user provides types. Can do much
more than CLs defmethod
. Of course defmethod
and in Julia, typed functions can fill much
of the role, selecting versions of an overloaded function instead of clauses.
cond
fills the if .. .. elseif .. ., elseif ... else .. end
-like stuff.
with-open-file
, with-input-from-string
Opens streams and closes them at the end of the macro body. Very useful. I have one, planning to replace it with plain with
so you can do @with open(....) begin .. end
and a with_end(io::IOStream) = close(io)
, basically the overloaded function can catch anything.
Otherwise, all of these easily covered by Julia's macros. (i already did some)
values
is somewhat like (a,b)
notation but is hugely different in that you basically need
to use the multiple-value-bind
to get more than the first value back. values
as CL does it
can be handy when you want to return something that users might need but often just want to
discard. But doesn't seem all that valuable.
iterate
is a library, for the record. Thought they should be mentioned. They're ... not
horrible but i dont really like them either. for
syntax plays some of the same roles in
Julia.
Note that there are more libraries in CL that make various sorts of binding easier. (had a 'phase' wasting time making stuff like that use none now)
You can make named blocks (block name ...body..)
and basically get out of any named
block with (return-from name return-value)
(local)functions, macros and methods are also
blocks. (prog
does full gotos, but people dont like gotos anyway.)
This macro allows you to ensure an expression is executed even if a return
or return-from
is called:
(block ska
(unwind-protect
(progn (print :a)
(return-from ska :return-something))
(print :b))) ;This will be called despite returning above.
For instance it is used when anything is cleaned up for you by a macro or function(taking a function as argument) I think this one is pretty important.
For instance lispbuilder-sdl has
with-sdl
if they're about creation and then destruction after you're done, destructors might
be able to perform the same role. Most libraries like that have some with..
macro.
Uses symbol-macrolet
to attach accessing struct/class members to symbols. the struct.member
notation is pretty short,(certainly shorter than (slot-value obj 'slot)
) but getting them
this may still be interesting to have in Julia.
Opens streams and closes them at the end of the macro body. Very useful. (destructors could do it?)
Julia throws a lot of line numbers in. So autodoccers should be able to find them and use them
for autodocumentation. (I do not know how get a 'hook' on macroexpansion yet something like
macroexpand-hook
, but i found that weak, so i made
this(shameless plug).
I dont use it basically ever tbh, but it is awesome. It shows you the assembler bytecode or whatever such the CL implementation produces 'upon seeing that value'.
Annoying is to see how short it is but yet you cannot make a few-kilobyte binary with the compiler. -_-
Alexandria is an oft-used macro for various function/macros that are a bit lacking in the CL spec.
Various ways to 'fill in a variable' infront of in the back of a function or to compose
functions. Can be slightly tricky to read; i just use one layer of these and proceed to
lambda
after that, but can make defining functions more convenient.
An more flexible but 'uglier-code-producing' way to the same is to access lambda
quickly and
without making a parameter list, by using numbered parameters.
Often you're only interested in a variable if it is non-nil
, that is what these are for.
In Julia things are a bit different; Julia requires a Boolean
type. Still something like
if (x = 3)==3
x
end
Seems to work; basically allowing binding of new variables anywhere.
with-gensyms
also, it is covered by a,b = gensyms(2)
Automatic memoization. Never ended up using it, but sounds neat.
Allows you to write code to write html inside a lispified html form that writes other html you want to write.