freenode/#lisp - IRC Chatlog
Search
20:55:23
earl-ducaine
CL macrologists! I'm trying to write a macro that transforms a lambda list into an alternate lambda list and function body wrapper, within the context of a macro. E.g. https://gist.github.com/earl-ducaine/f510eb0091d04e2d0131cffe080f5d28
20:56:28
earl-ducaine
I'm having that familiar feeling of having the macro 90% written, then 50%, then wondering whether what I'm attempting is possible at all. :)
21:01:37
aeth
earl-ducaine: Unless I'm reading your requirements wrong, destructuring-bind does everything you want for free (only downside is that it *might* be slower)
21:03:45
aeth
The only difference is that that would require the list to be of length 3 and using nth does not (your approach doesn't care about the tail). You can implement not caring about the tail in destructuring-bind with (medium pathname options &rest rest) (declare (ignore rest))
21:04:10
earl-ducaine
Is there any way of doing that in the context of a macro? The reason for my need is that I'm trying to convert some old flavors code, and I'd like to rewrite the flavor defmethods into CLOS defmethods
21:05:41
aeth
I think it would look something like this: `(defun ,my-function (&rest rest) (destructuring-bind ,lambda-list rest (list ,@lambda-list))
21:06:14
aeth
The only problem is that destructuring-bind's lambda list is very similar to a macro's lambda list, so it would permit nested things like (foo (bar baz))
21:07:28
aeth
and, yes, you'd want to use gensym instead of rest, even though it doesn't really matter because there's no ,@body and even if you had an internal rest in your lambda list, it would use the inner rest from the destructuring-bind, not the outer rest
21:08:44
aeth
(let ((rest (gensym))) `(defun ,my-function (&rest ,rest) (destructuring-bind ,lambda-list ,rest (list ,@lambda-list)))
21:10:31
aeth
The only thing you might want to do differently from phoe's version is (let ((rest (gensym "REST"))) ...) instead of (let ((gensym (gensym))) ...)
21:11:57
earl-ducaine
Truly awesome. Thanks again! Looking at it I can't even remember why I thought it was so difficult. :)
21:13:31
aeth
The one catch about destructuring-bind is that sometimes it's inconvenient, especially when combined with e.g. mapcar or defun, because you often want the function to have one, temporary argument.
21:13:48
aeth
For lambdas (e.g. use in mapcar) I wrote this: (defmacro destructuring-lambda (lambda-list &body body) (let ((expression (gensym))) `(lambda (,expression) (destructuring-bind ,lambda-list ,expression ,@body))))
21:14:34
aeth
Then I can (mapcar (destructuring-lambda (foo bar baz) `((,baz ,bar) ,foo))) some-part-of-a-macro)
21:15:04
aeth
It saves two lines and a temporary variable and is very similar to phoe's solution for defun
21:15:50
aeth
If you don't write macros to save yourself two lines (multiplied by dozens of times in a large program), you might as well be coding in Java. :-)
21:18:32
aeth
I personally find that most macros have some structure to their s-expressions, and you either want to transform that to another structure (e.g. maybe a series of function calls) or you want to create a data structure of standard-objects/structure-objects/arrays/etc. at compile time. So destructuring-bind is incredibly useful imo.
21:21:08
aeth
stylewarning: Imo any pattern that repeats itself constantly (like a temporary variable for destructuring-bind in a one-argument lambda) is a place where bugs can easily happen.
21:23:14
earl-ducaine
The paragraph I was remembering was in cltl, related to parse-macro, a suggested function that didn't make it into the standard. https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node102.html
21:23:40
earl-ducaine
In particular: However, parse-macro is worth having anyway, since any program-analyzing program is going to need to define it, and the implementation isn't completely trivial even with destructuring-bind to build upon.
21:25:31
aeth
earl-ducaine: It looks like the function phoe wrote *is* parse-macro, but without the environment stuff?
21:27:11
aeth
I'm surprised there isn't one for lambda, like the one I wrote. Happens all the time in mapcar.
21:36:42
Bike
parse-macro is more complicated because it handles &whole differently from destructuring-bind
21:58:48
Duns_Scrotus
why does funcall look in the function namespace but apply looks in the value namespace
23:40:24
Xach
Shinmera: http://report.quicklisp.org/2018-08-29/failure-report/staple.html#staple-server has my log
2:41:21
lyf[kde]
Using CSP, I can wrap the continuations, to implement event loops and to optimize tail calls, but CSP is handly only when it comes to tail calls.
3:26:42
lyf[kde]
Here is one creative implementation: https://github.com/mystor/breaktarget/blob/master/src/lib.rs This library (in Rust) uses panic unwinding to its advantage.
3:32:17
no-defun-allowed
panic! is pretty much "all shit went south" so it seems like a bad idea to reuse that for normal program flow
3:39:28
lyf[kde]
Stack as in BFS, DFS... In DFS you have a todo queue. In BFS you have a todo stack. You can also implement DFS as a recursive function without the todo collection.
3:40:27
Bike
you can use an explicit stack in a limited context to do something like continuations, s ure
3:41:34
ealfonso
is there a built-in "which" in CL/sbcl to find the absolute path to an executable given its name? I tried looking at SB-EXT:RUN-PROGRAM's implementation which accepts a :search flag: https://github.com/sbcl/sbcl/blob/e98378ca004ef6d101b384f6c3130f24b7a1bc1f/src/code/run-program.lisp but can't figure it out
3:56:46
mange
lyf[kde]: If you're trying to implement call/cc in another language you could try something like http://www.schemeworkshop.org/2007/procPaper4.pdf, but it's pretty hard to do manually.
5:55:31
aeth
stylewarning: It depends. If it's something like shortening names to make them easier to type, that usually makes things worse, just get some form of autocomplete. But if it's removing a variable, that often makes the code clearer imo.
6:01:53
aeth
stylewarning: mapcar itself is sort of an example of this. It's basically just maplist where you're calling car on every variable.
6:02:05
aeth
a one variable version could be implemented as trivially as: (defun mapcar* (function list &rest more-lists) (declare (ignore more-lists)) (maplist (lambda (x) (funcall function (car x))) list))
6:59:30
slyrus1
Shinmera: it's probably not relevant given iclendar, but did have you seen my https://github.com/slyrus/soiree/blob/master/icalendar.lisp
8:08:36
Shinmera
iclendar can't parse things as it is, only produce them, but I would certainly welcome a parser addition to it.
8:14:09
slyrus1
It would be great if all of these were combined into one library/suite that could read and write icalendar/vcard and talk to caldav/carddav servers.