freenode/#lisp - IRC Chatlog
Search
16:33:08
pjb
Well, unless you want the newly bound variables to be of the same kind. Then you need a binding macro.
16:39:13
pjb
Fade: It's just lack of CL knowledge on the part of swig maintainres. Some lisper should volunteer.
16:39:34
shka_
when writing a function that considers two cases, one of each let's say signals condition and the second actually does something more complex
16:39:59
pjb
Fade: on the other hand, so far swig hasn't given be good results. For example, it doesn't support packed structures, so it generates wrong cffi.
16:40:41
Fade
I was not using it for something new, I was looking at orthecredence's libsodium bindings, which use swig.
16:42:32
jackdaniel
shka_: the latter with return-from improves readibility if your function body has nesting bigger than 2-3 levels
16:53:12
shka_
what do you think about situation when function body is not deeply nested but slightly long, let's say 30 lines of code for the ELSE case?
17:40:38
sjl_
Depending on what you're checking, sometimes you can do it another way. E.g. instead of (defun foo (x) (when (null x) (error "Cannot foo a NIL")) (whatever x 10)) you could replace the null check with (defun foo (x) (check-type x (not null)) (whatever x 10))
18:02:40
Bike
i think you are confused about other things. (loop for header-item in (head page) do `(,header-item)) does not collect anything. In fact, it does nothing.
18:07:03
Bike
if i'm reading the spineret documents correctly, you'll need to use the :attrs argument, and return a plist (still one value)./
18:14:10
_death
values-list.. but in this case all you need is to (spinneret:with-html-string (:html (dolist (x '("read" "the" "docs")) (:tag :name "p" x))))
19:56:46
boeg
I was looking at rackets documentation and it seems to have a very impressive gui story. Whats the gui story for common lisp?
20:03:22
aeth
bexx: Get ECL or CLISP and use that to bootstrap, or use a generic Linux SBCL binary... iirc
20:12:27
aeth
Lycurgus: The question was for a distro without one, though. Also relevant for e.g. people making the binary for the distro
20:14:43
aeth
Hmm... Can Lisp-as-a-.SO greatly reduce memory consumption when more than one Lisp image is running at the same time from that Lisp? Does this exist in practice in e.g. ECL?
20:24:48
stacksmith
aeth: I doubt it makes much of a difference, since most of the memory is used as a GC'd object space, not code.. I can't imagine multiple OS-level instances sharing the same object space...
20:27:27
aeth
I was just thinking that e.g. if you had stumpwm, a CL-based Emacs, and an inferior-lisp (the third is not necessary, unlike in GNU Emacs, but it would still be nice not to crash the editor if you had a serious bug) then that's 3 CLs running at once.
20:31:30
aeth
So we're fine until someone has a CL web browser and a CL terminal and a CL POSIX shell and a CL...
20:33:21
aeth
Actually, though, I think 2-3 is all you need to run simultaneously. CL desktop applications could probably use a common CL daemon sort of like Emacs Server.
20:45:07
PuercoPop
aeth: but then you loose the advantage of being able to communicate by passing CL values around and are back to using serializations like in unix-land
20:49:57
aeth
PuercoPop: You do want at least 2 CLs running no matter what if you're doing development since you can easily crash a CL, e.g. through CFFI stuff. inferior-lisp is a feature, even with a CLemacs.
20:50:10
PuercoPop
aeth: if you have everything in the same image calling the 'editor' would be akin to a function call
20:51:00
jackdaniel
shared objects mostly reduce module duplication (and eventual inconsistency), I don't think they do much to memory consumption
20:51:01
PuercoPop
so for example, the way slime/swank communicate is by passing around s-exps as strings, not as the values in the running image
20:52:19
aeth
PuercoPop: Right, but if developing something in the editor brings down everything from the window manager on up, that's basically the Windows 95/98 experience all over again.
20:54:02
jackdaniel
common lisp has elaborate condition handling facilities, so unless there are hidden issues in the implementation it should be possible to wrap each application in handler-case and *not* bring everything down
20:54:47
jackdaniel
it is like saying that editor may crash kernel and everything goes down. sure, if you manage to segfault linux then you bring down x11
20:59:12
PuercoPop
aeth: I do understand the importance of what you are saying and I agree that it is probably the way to go. I just wanted to note the isolation is not without a cost. Like f/e writing a dmenu clone in Lisp. I would prefer if it could call it from inside StumpWM w/o shelling out
21:00:56
pfdietz
To debug the macro, try using macroexpand on a form that uses the macro: (macroexpand '(when (foo) (bar))) ==> the code with the WHEN macro expanded
21:51:43
dmiles
shka__: oh i see, i thought you were telling me about a list datatype yesterday.. you meant the trail
21:56:18
dmiles
using arrays in the case of a thing that resizes millions of times per operation is funny premature optimization i never understood :P
22:06:01
dmiles
the reason for use of arrays in some prolog impls is that the bindings can be undone by just moving a fill pointer
22:07:17
dmiles
but in the case of undo closures that even have to be ran tun undo/unwind the arrays dont make as much sense
22:07:50
dmiles
but in the case of undo closures that even have to be ran to enact a undo/unwind the arrays dont make sense
22:11:29
dmiles
in 1998 i merged a the OCKB Lisp impl (written in Java) and Tarau's KeneralProlog (and written in Java) .. And found this Zen in making the lisp env and prolog trail work together
22:12:58
dmiles
but it sucks that in real life (not doing this from the backend language) it is not beautifull as it should be
22:15:43
dmiles
if i had help porting CYC back into Lisp (instead of translated Lisp) I'd spend the time wuth jackdaniel's trying to revive ECL's WAM engine
22:18:48
pjb
seok: you could, if you passed an object to render-page, instead of a symbol or a sexp.
22:23:53
pjb
read https://github.com/informatimago/lisp/blob/master/common-lisp/html-generator/html-generators-in-lisp.txt
22:31:10
pjb
Macros are functions that work on programs, not on data. They will take program chunks, such as variable names, or expressions, and generate a new expression from them. And they work during compilation TIME. Data is known at run TIME, and you will have functions working on the data. But this run TIME can occur THOUSANDS of YEARS after the compilation!
22:32:52
pjb
Of course, there may be some confusion here, since data is program and program is data. Of course, the variable name, or the expression are lisp data (symbols, lists, etc). And you can also consider any data as program that a macro can interpret and use to generate the lisp expression. But the problem is that those data will have to be known at compilation TIME (remember THOUSANDS of YEARS before run-TIME).
22:33:17
pjb
So it can work only on universal constants data, or old, historic data. Not on new data processed at run-TIME.
23:49:23
pjb
seok: there's what we call the arrow of time, and it cannot loop back (without a time machine).
23:50:24
pjb
seok: so it cannot be first, and therefore we cannot use the value resuting from this evaluation BEFORE, in the macro.
23:51:43
pjb
seok: now, there are different theories of time. In some case, time machines don't project you just "back in time", but actually will fork a new universe from that time in the past. In a way, it makes a copy of the old universe for you to use now. It's not really time travelling, it's universe copying and forwarding.
23:54:09
pjb
(defmacro double (x) `(list ,x ,x)) (defun compute-value-and-double-it () (eval (list 'double (random 10)))) (compute-value-and-double-it) #| --> (4 4) |#
23:55:04
pjb
Notice that (double (random 10)) #| --> (8 4) |# we cannot send back in time the result of the evaluation of (random 10) (which was 8 the first time). Here the macro expands to (list (random 10) (random 10)) and this is evaluated at run-time.
23:55:46
pjb
so instead we compute (random 10) in compute-value-and-double-it, and use it to build an expression such as (double 3) and call eval to copy the universe and fork out to a new evaluation!
23:57:02
pjb
In this simple case, we could write the macro as (defmacro double (x) (let ((vx (gensym))) `(let ((,vx ,x)) (list ,vx ,vx)))) and use (double (random 10)) but x would still have been bound to (random 10), not to 3 or 5, and when you write such macro, it's a strong hint that you should have written a function (as I already told you a lot!). (defun double (x) (list x x)).
23:57:56
pjb
Now, if you have a (real) time machine, just tell us, and we will interface it with a CL system so you can do what you want!
0:10:49
aeth
pjb: (1) alexandria has some macros to simplify that and (2) I think Common Lisp can run on a real time machine
0:11:59
dialectic
seok: Helpful hint. Only write your program using functions. When you find yourself repeating the same thing over and over, then you can reach for defmacro.
4:04:05
vsync
dialectic: though I find it handy to (partly) write in the language I wish I had... or is that an advanced technique?
4:06:04
vsync
and I would say as well, when you do write macros, write them in terms of functions as much as possible... that tripped me up earlier on when I first got really into macros
4:08:26
vsync
problems I ran into were: 1) doing too much restructuring or especially building of code constructs "inline" in the macro rather than factoring out; 2) having all the generated code be inline even when it could be factored out into a function call
4:09:13
vsync
helps debugging to have my macro call functions to do its work and the generated code sometimes call functions to do its work... and found the resulting code clearer as well
4:09:31
aeth
Basically never write macros. Eventually you'll find some boilerplate that will frustrate you enough that you'll break that rule. Some exceptions could be made for ones that fit established patterns like define-foo, with-foo, and do-foo
4:10:51
aeth
And, yes, if you're writing functions, put most of the generation work into functions or at least LET variable bindings and have the actual quasiquoted macro look like this: `(let ,(generate-bindings foo bar) ,@(pre-body bar baz) ,@body ,@post-body)
4:11:17
vsync
aeth: would you support those constructs being recognized as first-class things with language support, e.g., DEFDEFINER, DEFWITHER?
4:12:19
aeth
A define-define that covers 90% of the cases when you want to make a defun or global defparameter/defvar/defconstant, as well as a define-with that covers the basic with-pattern of unwind-protect, would help a lot
4:12:36
aeth
define-do would be harder since you could base your do-foo on loop, do, tagbody/go, or even higher order functions like map
4:14:16
aeth
vsync: DO is structurally an extremely simple TAGBODY with GO and a LET binding around it
4:15:00
aeth
vsync: You can just use the implicit tagbody in DO and confuse people (and probably tools like Emacs)
4:15:23
aeth
dialectic: people only hate DO because they never use it... you can do amazing things with it
4:15:56
aeth
the thing DO gets you is the ability to MACROEXPAND-1 it and see how it is implemented, and how it is probably implemented with only a few differences in other implementations
4:16:26
dialectic
I am an open minded person. I let DO into my life. DO let me down. I no longer use DO.
4:16:56
dialectic
Any macro which makes me commit to memory a totally arbitrary syntax is a design failure.
4:17:12
aeth
The best DOs are zero-body DOs. If you have a body (that's more than just declarations) you're probably doing something that would be clearer with some other iteration form (or defining your own)
4:18:28
dialectic
A DO that has no body is almost always clearer as a LOOP anyway. And in a loop I have the option of splitting the initialization and iteration.
4:19:14
dialectic
And... I can also throw in arbitrary body forms, interspersed with the iteration code. It is just so much more readable, but I get this is preference.
4:19:35
aeth
dialectic: A DO is only clearer as a LOOP if you don't think that you should use the simplest iteration that accomplishes the task
4:20:19
aeth
LdBeth: map/mapcar is extremely clear... if the thing you're iterating with is a function, like (mapcar #'first list)
4:22:02
aeth
dialectic: the only simple iteration that works fine in DO that I think is clearer in LOOP is something like where you're reading because there you have (foo (read-whatever ...) (read-whatever ...)) vs. :for foo := (read-whatever ...)
4:23:19
aeth
LOOP could give you a deleting unreachable code note/warning if the ":for foo := (read-whatever ...)" is only run once since it's technically generating two things, too.
4:24:29
aeth
dialectic: because I want my editor to highlight it like a keyword, and, as an added benefit, I get a pseudo-Pascal :=
4:25:30
aeth
LOOP is a mini-ALGOL-like language where e.g. "for" is a keyword (in non-Lisp terms) but by making it ":for" it's also a keyword in Lisp terms and is highlighted specially
4:26:41
aeth
dialectic: and besides, the first time I used the LOOP example with keywords, I didn't put "s around it or otherwise distinguish it, but it was immediately clear that the "for" wasn't prose
4:32:45
aeth
LdBeth: I love messing with lots of parentheses, and as much as I've gotten used to LOOP, I don't like that it's :for foo :in bar instead of (:for foo :in bar)