Xach changed the topic of #commonlisp to: Common Lisp, the #1=(programmable . #1#) programming language | Wiki: <https://www.cliki.net> | IRC Logs: <https://irclog.tymoon.eu/libera/%23commonlisp> | Cookbook: <https://lispcookbook.github.io/cl-cookbook>
igemnace has quit [*.net *.split]
theBlackDragon has quit [*.net *.split]
Qwnavery has quit [*.net *.split]
molson has quit [*.net *.split]
raeda has quit [*.net *.split]
terrorjack has quit [*.net *.split]
fengshaun_ has quit [*.net *.split]
sander has quit [*.net *.split]
pieguy128_ has quit [*.net *.split]
rgherdt has quit [*.net *.split]
snits_ has quit [*.net *.split]
minion has quit [*.net *.split]
mmk2410_ has quit [*.net *.split]
jmercouris has quit [*.net *.split]
stylewarning has quit [*.net *.split]
mister_m has quit [*.net *.split]
sp has quit [*.net *.split]
frgo has quit [*.net *.split]
jgkamat has quit [*.net *.split]
saturn2 has quit [*.net *.split]
travv0 has quit [*.net *.split]
Odin- has quit [*.net *.split]
jemoka has quit [*.net *.split]
defaultxr has quit [*.net *.split]
totoro has quit [*.net *.split]
cognemo has quit [*.net *.split]
specbot has quit [Remote host closed the connection]
mmk2410 has joined #commonlisp
rgherdt has joined #commonlisp
Qwnavery has joined #commonlisp
stylewarning has joined #commonlisp
snits has joined #commonlisp
jmercouris has joined #commonlisp
travv0 has joined #commonlisp
mmk2410 has quit [Changing host]
mmk2410 has joined #commonlisp
igemnace has joined #commonlisp
Odin- has joined #commonlisp
Qwnavery has quit [Changing host]
Qwnavery has joined #commonlisp
defaultxr has joined #commonlisp
travv0 has joined #commonlisp
travv0 has quit [Changing host]
specbot has joined #commonlisp
minion has joined #commonlisp
cognemo has joined #commonlisp
pieguy128 has joined #commonlisp
frgo has joined #commonlisp
saturn2 has joined #commonlisp
molson has joined #commonlisp
sander has joined #commonlisp
totoro has joined #commonlisp
Qwnavery has quit [Client Quit]
totoro has quit [Changing host]
totoro has joined #commonlisp
jgkamat has joined #commonlisp
fengshaun has joined #commonlisp
jemoka has joined #commonlisp
raeda has joined #commonlisp
Qwnavery has joined #commonlisp
terrorjack has joined #commonlisp
sp has joined #commonlisp
theBlackDragon has joined #commonlisp
Yehowshua has quit [Ping timeout: 256 seconds]
Lord_of_Life has quit [Ping timeout: 260 seconds]
Lord_of_Life has joined #commonlisp
Guest-liao has quit [Ping timeout: 256 seconds]
Guest-liao has joined #commonlisp
jasom has quit [Ping timeout: 268 seconds]
taiju has joined #commonlisp
mfiano has joined #commonlisp
mfiano has quit [Remote host closed the connection]
mfiano has joined #commonlisp
jasom has joined #commonlisp
Oladon has quit [Quit: Leaving.]
robin has quit [Ping timeout: 245 seconds]
Yehowshua has joined #commonlisp
robin has joined #commonlisp
aeth has quit [Ping timeout: 265 seconds]
aeth has joined #commonlisp
taiju has quit [Ping timeout: 245 seconds]
taiju has joined #commonlisp
igemnace has quit [Remote host closed the connection]
Guest7490 has joined #commonlisp
<Guest7490> Hi. Has anybody implemented the SANE network protocol in lisp?
brettgilio has quit [Quit: Leaving...]
herlocksholmes has quit [Quit: Leaving...]
herlocksholmes has joined #commonlisp
brettgilio has joined #commonlisp
Guest-liao has quit [Ping timeout: 256 seconds]
raeda has quit [Quit: Leaving]
Qwnavery has quit [Quit: WeeChat 3.3]
taiju has quit [Ping timeout: 264 seconds]
Bike has quit [Quit: Lost terminal]
Guest-liao has joined #commonlisp
ahc71 has joined #commonlisp
tyson2 has quit [Remote host closed the connection]
taiju has joined #commonlisp
Guest7490 has quit [Ping timeout: 245 seconds]
Qwnavery has joined #commonlisp
Qwnavery has quit [Client Quit]
Yehowshua has quit [Ping timeout: 256 seconds]
Oladon has joined #commonlisp
rogersm has quit [Read error: Connection reset by peer]
rogersm_ has joined #commonlisp
<beach> Good morning everyone!
Guest-liao has quit [Ping timeout: 256 seconds]
waleee has quit [Ping timeout: 268 seconds]
Guest-liao has joined #commonlisp
lottaquestions has joined #commonlisp
ebrasca has joined #commonlisp
Guest-liao has quit [Ping timeout: 256 seconds]
semz has quit [Ping timeout: 260 seconds]
semz has joined #commonlisp
hendursaga has quit [Remote host closed the connection]
hendursaga has joined #commonlisp
semz has quit [Ping timeout: 246 seconds]
akoana has left #commonlisp [#commonlisp]
ebrasca has quit [Remote host closed the connection]
Guest-liao has joined #commonlisp
semz has joined #commonlisp
Skyfire has quit [Quit: WeeChat 3.3]
lisp123 has joined #commonlisp
Guest-liao has quit [Ping timeout: 256 seconds]
dec0d3r has joined #commonlisp
<lisp123> At what stage should one start adding error checking and conditions to code?
<lisp123> Its a lot of burden at earlier stages of prototyping, and many internal functions don't need them because their inputs & outputs are somewhat certain
<lisp123> But of course once you get to the user input stage, its very important
<beach> I would say "as early as possible", and most of the checking should be at the protocol level so that errors don't propagate and make debugging harder.
<beach> Yes, you don't do error checking for "internal" functions.
<lisp123> beach: Thanks, by protocol do you mean external I/O?
<beach> It's a generalization of "interface".
<beach> This is the general idea, but it could be hard in some cases, where "hard" could mean "computationally too expensive".
<lisp123> Thanks!
<beach> Sure.
<beach> Bertrand Meyer described this idea and called it "programming by contract".
<beach> His work is worth reading.
<beach> Or "design by contract", rather I guess.
charro has quit [Ping timeout: 264 seconds]
<beach> In fact, every serious programmer should already have read his work, and if not, should read it urgently.
taiju has quit [Ping timeout: 246 seconds]
<beach> But then, we know what the reality of software development looks like.
easye has joined #commonlisp
<lisp123> beach: Thanks, I will read
<White_Flame> lisp123: add error checking when the default lisp error reports stop being helpful because they're too low level, or occur too late :-P
<White_Flame> and those 2 aspects guide what should be checked early
<White_Flame> so you can predict what actually needs to be checked
<lisp123> White_Flame: lol, you can guess why I started this conversation, I have no idea of how to solve this current error ;)
<White_Flame> then add more error checking! ;)
Qwnavery has joined #commonlisp
<lisp123> White_Flame: lol
Qwnavery has quit [Client Quit]
bcasiello has quit [Ping timeout: 245 seconds]
<lisp123> That's basically me right now
<White_Flame> add error checking for things you think are obviously correct and don't need checking
<lisp123> I don't know which function is causing the error, so I'm just randomly adding error checking for each :)
<lisp123> (I kid a bit, its not that random, but its definitely very inefficiently done)
<hayley> You don't have backtraces?
<lisp123> hayley: I'm getting an error when compiling the file vs. evaluating the form (its a reader macro). So I suspect its to do with the whole read time vs. compile time vs. run time
<beach> lisp123: I recommend against that way of doing it. It is going to add a lot of noise to functions that should never be called with unknown arguments.
<hayley> You'd still get a backtrace if you had a reader error.
<beach> lisp123: If you don't know what function is causing the error, then you probably haven't added checks at the protocol level.
<hayley> For example, if I just type ) at a REPL on SBCL, I can see that the error is caused in SB-IMPL::READ-RIGHT-PAREN, which was called by READ-MAYBE-NOTHING...
<lisp123> beach: Yes, agree, one learns from painful experiences :) For today, I want to just solve this error, so I'm adding print and error checking everywhere; but I will refactor the code properly in the next few days
<lisp123> hayley: Thanks. I got "READ error during COMPILE-FILE. The value NIL is not of type SB-INTROSPECT:DEFINITION-SOURCE", so now I'm just trying to figure that out
<hayley> That does not look like a backtrace to me, though it is more information than "I got an error".
<lisp123> But no call stack, sorry I think I confused what you meant by backtrace vs. call stack
pranavats has left #commonlisp [#commonlisp]
dec0d3r has quit [Remote host closed the connection]
<lisp123> Okay, so what helped was removing (ignore-errors ...), definitely not going to take that shortcut again
<lisp123> hayley: So I get backtraces when I evaluate the code, but not when I compile the file
Guest-liao has joined #commonlisp
<lisp123> Are we meant to get backtraces when compiling a whole file (slime)?
<lisp123> (or is there a way to turn that setting on)
<hayley> I'm not sure after reading the CLHS page on COMPILE-FILE.
<hayley> But reader errors should be the same irregardless of whether you are calling (say) LOAD or COMPILE-FILE. So just stick with LOAD until it works.
<lisp123> hayley: Thanks! Will do
gxt_ has quit [Remote host closed the connection]
gxt_ has joined #commonlisp
pranavats has joined #commonlisp
edgar-rft has quit [Quit: Leaving]
taiju has joined #commonlisp
Guest-liao has quit [Quit: Client closed]
pve has joined #commonlisp
Oladon has quit [Quit: Leaving.]
aartaka has joined #commonlisp
dec0d3r has joined #commonlisp
shka has joined #commonlisp
_whitelogger has joined #commonlisp
hendursa1 has joined #commonlisp
hendursaga has quit [Ping timeout: 276 seconds]
paule32 has joined #commonlisp
casionaut has joined #commonlisp
Guest-liao has joined #commonlisp
hendursa1 has quit [Remote host closed the connection]
hendursa1 has joined #commonlisp
amb007 has quit [Ping timeout: 264 seconds]
amb007 has joined #commonlisp
mfiano has quit [Remote host closed the connection]
mfiano has joined #commonlisp
mfiano has quit [Remote host closed the connection]
mfiano has joined #commonlisp
mfiano has quit [Remote host closed the connection]
mfiano has joined #commonlisp
mfiano has quit [Remote host closed the connection]
Alfr has quit [Quit: Leaving]
mfiano has joined #commonlisp
cage has joined #commonlisp
mfiano has quit [Remote host closed the connection]
mfiano has joined #commonlisp
casionaut has quit [Quit: o7]
molson has quit [Ping timeout: 268 seconds]
edgar-rft has joined #commonlisp
Alfr has joined #commonlisp
igemnace has joined #commonlisp
taiju has quit [Ping timeout: 245 seconds]
taiju has joined #commonlisp
lthrope has joined #commonlisp
taiju has quit [Ping timeout: 268 seconds]
lthrope has quit [Quit: Client closed]
random-nick has joined #commonlisp
taiju has joined #commonlisp
tyson2 has joined #commonlisp
igemnace has quit [Remote host closed the connection]
domovod has joined #commonlisp
amb007 has quit [Ping timeout: 246 seconds]
amb007 has joined #commonlisp
ahc71 has quit [Quit: Client closed]
amb007 has quit [Ping timeout: 264 seconds]
didi has joined #commonlisp
didi has left #commonlisp [O bella ciao bella ciao bella ciao, ciao, ciao.]
Inline has joined #commonlisp
Lycurgus has joined #commonlisp
amb007 has joined #commonlisp
<beach> I started reading "Let Over Lambda", and the book is much better written than the other LOL book. But why on earth would the function GROUP be written as it is on page 14?
<beach> There are at least 4 problems with this 10-line code snippet.
<beach> First, the use of IF without an `else' branch.
edgar-rft has quit [Quit: Leaving]
<beach> Then the use of tail recursion rather than ordinary recursion.
<Lycurgus> https://letoverlambda.com/ is the other?
<beach> And the inner IF should test the base case first, not the recursive case.
<beach> There is only on "Let Over Lambda" I think, no?
<Lycurgus> i'm referring to "the other LOL book"
<hayley> Lycurgus: That is the website for the book Let Over Lambda, but it shares an acronym with Land Of Lisp.
<Lycurgus> ah
<beach> lucerne: The other LOL book is "Land of Lisp".
<Inline> the online pdf version does not have all chapters
<beach> Then the code uses SOURCE as a Boolean variable in the last IF.
<Inline> there's errata and a working stripped version of the source code too
<Inline> the book version of the source code might not work
<Inline> or be buggy
<beach> It seems to work.
<beach> GROUP seems to work.
<Inline> yeah, some of that initial material is from onlisp
<beach> But it has the problems I listed above. In particular tail recursion makes it very hard to follow.
<beach> Well, that might explain it, but he could have written a better version of it then.
<beach> Oh, and another problem: there is absolutely no reason not to handle the empty list as input.
<beach> When written properly, GROUP reads like a proof by induction. Not this version, though.
pjb has quit [Ping timeout: 260 seconds]
<hayley> There is a section on CL-PPCRE, and the book falsely states that the regex library compiles a Lisp form from a regular expression (in reality, it creates a chain of closures corresponding to a NFA corresponding to the regular expression).
<beach> Right, so the version in LOL is taken from page 47 of On Lisp, but Graham has a better version on page 389.
<beach> I was totally put off by this version of GROUP, but now that I see it is copied from elsewhere, maybe I'll continue reading.
<hayley> Or, at least, I cannot find a call to COMPILE or COERCE in CL-PPCRE which would compile any generated code. But it is irrelevant to the GROUP function.
vats has joined #commonlisp
McParen has joined #commonlisp
<semz> beach: Is there something by Meyer you'd recommend as a starting point?
cosimone has joined #commonlisp
<beach> semz: Hold on...
<beach> There is a new-ish book "Design by Contract". That sounds promising since it's the essence of what I said before.
<beach> But I haven't read that one myself.
Lycurgus has quit [Quit: Exeunt]
<beach> Hmm, maybe it's not a book.
<beach> OK, so let me tell you which one I was referring to before: Object-Oriented Software Construction.
Guest-liao has quit [Quit: Client closed]
s-liao has joined #commonlisp
aartaka has quit [Ping timeout: 246 seconds]
Bike has joined #commonlisp
Devon has joined #commonlisp
varjag has joined #commonlisp
srhm has quit [Read error: Connection reset by peer]
pjb has joined #commonlisp
srhm has joined #commonlisp
amb007 has quit [Ping timeout: 264 seconds]
amb007 has joined #commonlisp
Inline has quit [Read error: Connection reset by peer]
amb007 has quit [Ping timeout: 264 seconds]
amb007 has joined #commonlisp
<lisp123> beach: All yours comments make sense except one. Took me a while to switch from if to when for 1 case and arguably others may choose to resist). Also, I too used to use values of variables as a shortcut for boolean, but don't anymore
<lisp123> I didn't get your comment on tail vs. ordinary recursion though
<beach> WHEN or UNLESS should be used in a context where no value is needed, and there is only one branch for the test.
<beach> Almost invariably, when tail recursion is used, the result becomes so twisted that it is hard to understand.
<beach> Ordinary recursion can be made to look like a proof by induction.
Inline has joined #commonlisp
aartaka has joined #commonlisp
<beach> Handle the base case first. Then assume the induction hypothesis holds and handle the other cases.
<lisp123> beach: ^ yes, that's how I always do it (probably since a lot of example code in books do it that way, and FACTORIAL is the canonical example that everyone learns). What do you mean by 'tail recursion' then?
<lisp123> Seems very strange that (rec ...) appears above the other entry in the code, so I agree with you there - is that called tail recursion?
Lycurgus has joined #commonlisp
domovod has quit [Ping timeout: 245 seconds]
<beach> It is tail recursion when the recursive call is a tail call.
<beach> Sometimes, tail recursion is "natural", but often it is obtained by a transformation of non-tail-recursion, and then it looks artificial and hard to follow.
domovod has joined #commonlisp
<lisp123> Oh, I thought we were meant to write with tail call recursion? I've been using accumulators for that purpose but admittedly haven't focused on much on checking whether what I do is tail call recursive, but I read its something important to do
<lisp123> If you want time, I would be keen to see how it would look in 'ordinary recursion'
<beach> We are NOT meant to transform a perfectly good non-tail-recursive function into tail recursuve.
<beach> (defun ! (n) (if (zerop n) 1 (* n (! (1- n))))) is not tail recursivce.
<beach> And it is perfectly good because it corresponds to the definition of factorial.
<lisp123> Agree 100%, i've been doing just like you wrote
<beach> Good. Now turn it into a tail recursive version, and watch how it instantly becomes incomprehensible.
<lisp123> I've been lazy and haven't been doing that extra step in that case to make it tail call recursive, so I guess I should disregard that advice?
<lisp123> It makes it very disjointed to read
<lisp123> (let me find an example where I use accumulators, I only use them where it felt natural, not intentionally)
vats has quit [Read error: Connection reset by peer]
vats has joined #commonlisp
<Alfr> beach, (defun ! (acc n) (if (zerop n) acc (! (* n acc) (1- n))))
varjag has quit [Ping timeout: 264 seconds]
<beach> Exactly! Now it no longer corresponds to the most "natural" definition of factorial.
<Alfr> beach, I wouldn't say unrecognizable. But as this is CL, it may be bad anyway as the spec doesn't mandate unlimited tail calls.
<beach> First of all, the factorial function takes a single argument, so you have to do a LABELS.
<beach> Alfr: Oh, but you would use iteration in this case anyway. It is just an example.
<Alfr> beach, what do you mean?
<beach> So, yes, you are right, tail recursion won't help.
vats has quit [Ping timeout: 245 seconds]
<beach> You wouldn't use recursion (tail or otherwise) for something simple like factorial.
vats has joined #commonlisp
<lisp123> ehhh, I can't seem to find any examples where I used accumulators anymore...looks like I replaced a lot of them with loops
<beach> But assume this is Scheme. Compare (defun length (list) (if (null list) 0 (1+ (length (cdr list))))) to (defun length (list) (labels ((aux (rest acc) (if (null rest) acc (aux (cdr rest) (1+ acc))))) (aux list 0)))
<beach> The first version reads like a proof by induction.
<beach> Base case: the list is empty. Then the length is 0.
<beach> Induction hypothesis: we know how to compute the length of a list with 0 .. n CONS cells, and we are given a list with n+1 CONS cells. Add one to the length of the CDR of the list.
<beach> This is also the reason why you shouldn't write (defun length (list) (if (consp list) (1+ (length (cdr list))) 0))
waleee has joined #commonlisp
<beach> In a proof by induction, the base case is always stated first.
<lisp123> Agree
<beach> lisp123: So the second version of LENGTH above, is an example of artificial transformation of a "natural" recursive function into an incomprehensible tail-recursive one.
<lisp123> beach: Whilst I agree with you, one can say its a common enough way of writing that it isn't that hard to follow?
<beach> lisp123: But sometimes it is tail recursive anyway, like (defun no-numbers (list) (cond ((null list) t) ((numberp (car list)) nil) (t (no-numbers (cdr list)))))
<beach> One can say that, but it would be incorrect.
tyson2 has quit [Remote host closed the connection]
vats has quit [Read error: Connection reset by peer]
<beach> The point is that one should write code in order for it to be read by humans.
<beach> And one should make sure to avoid wasting time for those humans unnecessarily.
<lisp123> beach: We are NOT meant to transform a perfectly good non-tail-recursive function into tail recursuve. -> Is this because (a) the compiler can do it any way (because otherwise the argument is that the tail call version is more "efficient") or (b) should we use iteration in such problems?
<beach> It is because the result is incomprehensible so we are making life harder for the person reading the code.
<lisp123> The point is that one should write code in order for it to be read by humans. And one should make sure to avoid wasting time for those humans unnecessarily. -> Very true!!
pranavats has left #commonlisp [Disconnected: Replaced by new connection]
<random-nick> transforming a non-tail-recursive function into being tail recursive is pretty much using iteration
<beach> But yes, in Common Lisp, you should use iteration for "linear" problems.
pranavats has joined #commonlisp
<beach> random-nick: Semantically, yes, but not syntactically. And people read syntax.
waleee has quit [Ping timeout: 265 seconds]
<Alfr> lisp123, if you can use tail recursion, then you can use iteration, instead of calling your function with new arguments you could goto the start of it and update iteration variables and run the body again.
<beach> Exactly. It's a bit harder with mutual recursion of course.
<Alfr> lisp123, this also works the other way around, turning a loop into a tail recursive function.
waleee has joined #commonlisp
<lisp123> Can I just use 'ordinary' recursion or is that bad?
<lisp123> I prefer that to both in the example of factorial (and examples similar in nature)
<Alfr> lisp123, you can if you're sure that the data you feed it won't cause the program to run out of stack space.
<random-nick> oh I agree, I'm just saying that the exact same semantics of a tail recursive function can be written as a loop, so it's easy to write a loop instead
<beach> Maybe something like "natural" recursion is better. Then it can sometimes be tail recursion if that turns out to be "natural".
<beach> random-nick: Sure.
<Alfr> lisp123, thus non-tail recursive implementation of length for a list likely is a really bad idea.
<lisp123> Alfr: Got it!
<lisp123> Thanks all
<Alfr> lisp123, there's nothing wrong with recursion, but the way how implementations use a stack (of a certain size) may cause your program to fail on otherwise good input.
<beach> lisp123: An example of good use of recursion in Common Lisp is operations on a balanced binary tree.
<beach> lisp123: Then, the depth is proportional to the logarithm of the number of nodes, so you are unlikely to run out of stack space.
<beach> Also, binary search, of course. An even simpler example.
<lisp123> beach: That's a very nice example to keep in mind, thanks.
<beach> Though binary search is almost as clear when iteration is used.
<lisp123> Hmmm. I do quite like recursion on binary searches / binary trees and find iteration harder to follow there
<beach> For trees you pretty much don't have a choice.
<_death> example (alexandria:flatten (loop for x = '() then (list x) repeat 100000 finally (return x)))
<beach> Runs out of stack?
<_death> yes
<Alfr> _death, that's quite a degenerate tree.
<beach> Sure, but flatten should still work.
<_death> since alexandria is a popular utility library, maybe it's worth reimplementing flatten without recursion
<beach> Definitely. Won't be easy though.
<lisp123> ooooh I would be keen for a copy of that. I use flatten a lot
<_death> beach: eh? (let ((stack (list x))) (loop until (null stack) do ...))
<beach> That might work.
<Alfr> Does it only operate on trees? Wouldn't dfs do it, so manually maintain a stack?
<_death> that is dfs..
<_death> or well, depth-first traversal
waleee has quit [Ping timeout: 252 seconds]
<Alfr> _death, sorry, didn't see yours. (I don't read while typing my stuff, otherwise I tend to mix in some random words I just read.)
Inline has quit [Ping timeout: 268 seconds]
<_death> (defun flatten (tree) (let ((result '()) (agenda (list tree))) (loop until (null agenda) do (let ((item (pop agenda))) (typecase item (cons (setf agenda (nconc (list (car item) (cdr item)) agenda))) (null) (t (push item result))))) (nreverse result)))
<_death> not really tested
<lisp123> _death: Thansk!
<beach> _death: Won't that destroy the original list?
<beach> Oh, no, I see now.
<beach> You could use list* there, no?
<beach> ... instead of nconc I mean.
<_death> yes.. or two pushes
<beach> That too.
<_death> list* would be nicer.. for pushes you'd have to use the reverse order
<beach> Yeah.
<beach> Also, the first CONS cell on AGENDA will always be freshly allocated, right?
<beach> So then you can reuse it for the RESULT.
<beach> ... I mean, when the CAR of AGENDA is an atom.
Josh_2 has joined #commonlisp
<Josh_2> Hi hi
<beach> Hello Josh_2.
<Josh_2> is there a way to destructure an alist in a similar fashion to a plist like (destructuring-bind (&key a b c &allow-other-keys) '(:a a :b b :c c)) ?
<Josh_2> Hey beach
<_death> not sure what you mean.. you maintain a tail instead of push/nreverse but I dunno if it's worth it
<_death> *you could maintain
<beach> No, that's not what I mean.
<_death> beach: well, I doubt TREE would be an atom very often
<Bike> Josh_2: nothing standard
<beach> I mean, you PUSH a fresh CONS cell onto RESULT, but you throw away the firs one on AGENDA with POP.
<Josh_2> Bike: alright
s-liao has quit [Ping timeout: 256 seconds]
varjag has joined #commonlisp
tyson2 has joined #commonlisp
<beach> _death: But I think the first CONS cell on AGENDA is a freshly allocated one when the CAR is an atom, so that CONS cell is not part of the original tree.
<Bike> Josh_2: i think you could do it with optima/trivia, maybe
<Alfr> _death, maybe keep push, but then also push cdr after car onto agenda; I think that then result doesn't need to be reversed.
<Josh_2> Bike: thats alright, I'll just use let and assoc :P
waleee has joined #commonlisp
<beach> Alfr: NREVERSE is cheap though.
Skyfire has joined #commonlisp
<_death> Alfr: yeah, that could work
<Alfr> beach, still will visit all conses again. And walking the tree RNL isn't hard given _death's code above.
s-liao has joined #commonlisp
s-liao has quit [Client Quit]
waleee has quit [Ping timeout: 264 seconds]
<_death> git push #commonlisp-flatten alexandria
<_death> rotatef the args :/
Guest74 has joined #commonlisp
Lycurgus has quit [Quit: Exeunt]
<pjb> beach: in maths, the base case is not always the first one to be written down. Also, various programming methods leave the iteration initialization aka recursion base case as a last step in building loops/recursions. Notably, the exact initialization may depend on the iteration/recursive case.
<pjb> it's like in physics, the conditions to the limit. That often comes at the end of a problem.
<jackdaniel> git #commonlisp-flatten alexandria push ?
<_death> git-push is the command ;)
<pjb> Now one argument about the order of if branches, is to put the smallest alternative first.
<jackdaniel> _death: right you are, my apologies :p
<pjb> (the base case is often the smallest).
<pjb> For example, you can have recursions where there are several different base cases, but a single simple recursive case. In this situation, it could be better to put the recursive case first, and all the base cases next.
sm2n has quit [Remote host closed the connection]
sm2n has joined #commonlisp
<pjb> Josh_2: (destructuring-bind ((k1 . v1) (k2 . v2) . arest) '((one . 1) (two . 2) (three . 3) (four . 4)) (acons `(+ ,k1 ,k2) (+ v1 v2) arest)) #| --> (((+ ONE TWO) . 3) (THREE . 3) (FOUR . 4)) |# ;-)
Oladon has joined #commonlisp
Inline has joined #commonlisp
<pjb> Josh_2: there's no &alist keyword.
<Josh_2> yeh but I do not want to destructure the entire list
<pjb> Josh_2: you could write your own defun macro (and others, including destructuring-bind), that would add a &alist keyword to do something similar to &key for a-lists. But you LAMBDA-LIST-KEYWORDS is a constant, so you will have to shadow it too…
<_death> (destructuring-bind (&key ,@the-keys &allow-other-keys) (alist-plist ,alist) ,@body) ;)
<beach> _death: http://metamodular.com/flatten.lisp is what I meant.
<beach> _death: It reuses the CONS cell, so should CONS only about half of yours.
<_death> interesting.. in the atom case you could use shiftf
<beach> Oh, good idea.
<Bike> rotatef, i think
<beach> Maybe someone can work it out and post a better version?
amb007 has quit [Ping timeout: 264 seconds]
amb007 has joined #commonlisp
<beach> Maybe ROTATEF will make the temporary unnecessary.
<beach> Beautiful! :)
<_death> updated to make it a bit shorter
<_death> updated with a cosy DO :)
<beach> nreverse?
<lisp123> How come '() vs. nil?
<_death> no need since I used alfr's trick
<beach> Oh, OK.
<_death> lisp123: it signals to the reader that you want an empty list
<beach> lisp123: NIL means "false" or "default value". '() means "empty list", () means empty parameter list.
<beach> I think that's in the Common Lisp HyperSpec too.
<lisp123> I see, thanks. I will update my usage then
tyson2 has quit [Ping timeout: 246 seconds]
<beach> _death: That's a very nice version.
waleee has joined #commonlisp
<yitzi> lisp123: It's in the CLHS glossary under () as way to emphasize the use of nil as an empty list.
<beach> I can't remember where in the Common Lisp HyperSpec they mention the different ways of writing NIL.
<_death> someone should submit it to alexandria ;)
<lisp123> yitzi: Cheers
<beach> yitzi: No, I recall a complete list of all uses like 'nil nil '() ()
<beach> lisp123: Oh, and 'nil means the symbol NIL as a form.
<yitzi> beach: Understand.
<lisp123> That makes sense
<beach> clhs 1.4.1.4.4
<beach> lisp123: ^
<lisp123> beach: Thanks, that's a useful link. I will save it down in my bookmarks.
<beach> Sure.
<beach> _death: I guess using WITH LOOP clauses instead of LET will save a level of indentation. :)
<_death> beach: I already took care of that with DO :)
<beach> Oh, let me see...
<beach> Yes, I see.
<_death> sometimes DO is very compact and nice
<beach> I think this version beats the current one in Alexandria in all possible ways. :)
<_death> except a docstring
<beach> That one can be copied. :)
<_death> in the words of Bob Ross, "there".. "now we can flatten our happy little trees"
<beach> That was an interesting instance of collaboration between several (4?) people here.
<beach> We should do stuff like that more often.
<_death> ;)
<beach> It beats trying to sort out FFI problems or HTML templates. :)
<holycow> land of lisp, page 51 has a lit of how to write nil 4 ways
<holycow> heh
<holycow> found it
mister_m has joined #commonlisp
amb007 has quit [Ping timeout: 268 seconds]
heisig has joined #commonlisp
amb007 has joined #commonlisp
<Guest74> is there a preferred socket library? Looks like I'm implementing the sane network protocol and I'm only used to using sb-bsd-sockets.
<lisp123> pjb: "Now one argument about the order of if branches, is to put the smallest alternative first." -> That's sort of like how Elisp encourages. Perhaps RMS had the same view on it
waleee has quit [Ping timeout: 268 seconds]
waleee has joined #commonlisp
<Guest74> yitzi: thanks. Any idea if it can do multicast? I'd like my UPNP stuff to not be limited to sbcl.
<pjb> lisp123: possibly.
casionaut has joined #commonlisp
<yitzi> Guest74: no idea. You'd have to look at the docs and code.
apemangr has joined #commonlisp
vats has joined #commonlisp
<Guest74> yeah, I can't see it so I'm asking. I'm guessing :stream means a local socket? or is that possible? If you're not familiar with the library I'll stop asking.
<White_Flame> multicast is just an IP address, right?
<White_Flame> doesn't change the API
<_death> :stream means a tcp socket.. if you want udp, that's :datagram
<Guest74> so no unix sockets?
<_death> right.. I think it's a recurring issue with usocket
<Guest74> in sbcl multicast requires setting options on the socekt, multicast address and interface using some c struct.
<White_Flame> oh wait, yeah, was thinking broadcast, not multicast
<Guest74> unix sockets would be nice, but I can just get away with tcp for SANE.
waleee has quit [Ping timeout: 264 seconds]
<Guest74> but is there anything for unix sockets, especially being able to transfer fds in msg? It'd be nice to have that for clx so can do shared memory.
<_death> there are other libraries like iolib or fsocket (which has unix domain sockets but not datagram ones)
anddam has quit [Quit: WeeChat 3.3]
<_death> you could also choose to add them to usocket
peterhil has joined #commonlisp
<Guest74> interesting fsocket seems to provide multicast, so I could use that for UPNP.
<Guest74> I've already got hectares of yaks.
<Guest74> hrm, fsocket isn't in quicklisp.
bcasiello has joined #commonlisp
Guest75 has joined #commonlisp
anddam has joined #commonlisp
<Guest74> anybody know why stumpwm isn't being logged on libera? Still logged on freenode.
Guest75 has quit [Quit: Client closed]
tyson2 has joined #commonlisp
dstein64 has quit [Ping timeout: 252 seconds]
srhm has quit [Read error: Connection reset by peer]
srhm has joined #commonlisp
heisig has quit [Quit: Leaving]
dstein64 has joined #commonlisp
<Josh_2> Wish cl-json is there a way to disable encoding? I am trying to append the received json object to my request
<Josh_2> if I decode the body then encode it again it does not produce an identical string
Inline has quit [Ping timeout: 245 seconds]
shka has quit [Quit: Konversation terminated!]
<Josh_2> I need something like ((a . a)(b . b)(c . "noencoded"))
<Josh_2> I think I have had this problem before
<Josh_2> Actually I think I might be able to do this with jojo
apemangr has quit [Ping timeout: 264 seconds]
Inline has joined #commonlisp
Oladon has quit [Quit: Leaving.]
domovod has quit [Ping timeout: 245 seconds]
<Josh_2> Nope :cry:
<Josh_2> If I can't get this to work suppose I could just try and manually verify the signature
hendursa1 has quit [Quit: hendursa1]
hendursaga has joined #commonlisp
edgar-rft has joined #commonlisp
waleee has joined #commonlisp
apemangr has joined #commonlisp
macaw has joined #commonlisp
<lisp123> Anybody have any ideas on this: https://plaster.tymoon.eu/view/2688#2688
tyson2 has quit [Remote host closed the connection]
<_death> you can read more than one form
<lisp123> _death: Oh, I see. I currently have something like this (defun reader ... (read stream t nil t) ...), do I need to add a loop to keep reading until I hit #end or something?
<_death> you can do that, yeah
amb007 has quit [Read error: Connection reset by peer]
<lisp123> Thanks! So does that mean once the function associated with a macro-dispatch-character finishes, control is passed back to the "main" reader?
<_death> reading is a recursive process
tyson2 has joined #commonlisp
<lisp123> hmmm ok, I think I get it. Would you do it any other way vs. a loop I noted above (just want to see what possible techniques are out there)?
amb007 has joined #commonlisp
<_death> you have a character stream and you can read the thing you want to read however you want, so long as you don't overstep by more than one character (that's when you can unread-char)
<lisp123> Got it, thanks!
cage has quit [Remote host closed the connection]
cage has joined #commonlisp
bcasiello has quit [Ping timeout: 265 seconds]
tyson2 has quit [Remote host closed the connection]
<_death> I guess one technique, in some cases, is to use another (and another, and another...) readtable in your READ-calling read macro.. I wonder much code does that in the wild, beyond the first level
<lisp123> _death: Indeed, that sounds like a good way to do it
<lisp123> Was just looking at an example where JSON is parsed like that -> https://gist.github.com/chaitanyagupta/9324402 (the famous guide on reader macros)
<lisp123> Although creating nested levels of readtables definitely sounds like nice way to parse other languages which have their own syntax
bcasiello has joined #commonlisp
apemangr has quit [Quit: Leaving]
<_death> named-readtables is a nice library.. internally it has a with-readtable-iterator, which CL maybe should've had in some form
<lisp123> It is indeed
lisp123 has quit [Remote host closed the connection]
Guest74 has quit [Quit: Connection closed]
<Josh_2> How do I sign a message with ironclad? I have a public key that i have to download
<_death> (ironclad:sign-message private-key message)
<Josh_2> By default is that sha1?
<_death> sha1 is a hashing algorithm
<Josh_2> The signature i have to verify is rsa with sha256
<Josh_2> ye
<_death> that means the message is hashed using sha256, and then signed using rsa
<Josh_2> So I just has my string then use sign-message with the key?
<Josh_2> hash my*
<_death> (the hash is the message for signing)
lisp123 has joined #commonlisp
<Alfr> Josh_2, do you rally want to sign? Having a public key sound to me like you'd like to verify.
<_death> for example, here's signing a message in the context of the scuttlebutt protocol https://plaster.tymoon.eu/view/2689#2689
mister_m has quit [Ping timeout: 265 seconds]
<Josh_2> Uh yeh I think I need to verify
<Josh_2> sorry _death
<_death> I updated with verification code
<Josh_2> does ::public-key return a vector?
<_death> no, it's something like (make-instance 'ironclad:ed25519-public-key :y y) where y is the octet vector
<Josh_2> ah okay thanks
<_death> in your case, it'd be an rsa-public-key
<Josh_2> Okay tyvm I'll give it a shot
<Josh_2> Rsa-public-key has e and n
<_death> correct
<_death> e is often 65537
<Josh_2> and n will be my signature i have downloaded?
<_death> if it's something stupid like 3, it's bad
<_death> n is the modulus
<Josh_2> So how do I turn my downloaded cert into an rsa-public-key object?
<Josh_2> Sorry for the lame questions, the first time around this stuff is always cryptic to me
<_death> the signature is S=m^d (mod n)
<_death> you need to extract the key from the cert using some asn.1 library
mister_m has joined #commonlisp
<Josh_2> Alrighty
waleee has quit [Ping timeout: 260 seconds]
bcasiello has quit [Ping timeout: 260 seconds]
cross_ has quit [Remote host closed the connection]
<Josh_2> Hmm I tried the asn1 library made by Fukamachi, however when I call (asn1:decode ..) on my downloaded signature a condition is signalled :(
<Josh_2> I will try asinine
<_death> well, it depends on the format of your certificate
<_death> it could be in PEM format, which contains base64 of DER encoded data of the X.509 certificate
<_death> welcome to cryptographic world
<_death> if it's just a single cert that you need the key from, you can use the openssl tool or something
waleee has joined #commonlisp
<Josh_2> It is not, it maybe be a different signature each request
<_death> cl-tls may also be helpful, though I've not used it in this context
<Josh_2> from some example code I have found in C# they are using a class called X509Certificate2 for their cert
<Josh_2> idk if thats helpful
<Josh_2> alright i'll check cl-tls
waleee has quit [Ping timeout: 245 seconds]
casionaut has quit [Quit: o7]
<Josh_2> cl+ssl also has some x509 stuff
<_death> yeah, but very limited interface
<Josh_2> cl-tls is not in ql :(
<_death> post an issue ;)
<Josh_2> Maybe if it works
<Josh_2> Hmm, got an error 'expected asn.1 sequence'
Skyfire has quit [Quit: br]
<Josh_2> Okay I downloaded it to my machine, linux is reporting "Openssl PEM format"
Skyfire has joined #commonlisp
<_death> cl-tls also has some pem code
ahc85 has joined #commonlisp
<Josh_2> https://plaster.tymoon.eu/view/2690#2690 I had to convert what I downloaded back to text and then used cl-tls::parse-pem
<Josh_2> I assume that vector is my key?
<_death> (cl-tls:x509-decode (cdar (cl-tls::parse-pem (alexandria:read-file-into-string "/etc/ssl/certs/Hongkong_Post_Root_CA_1.pem")))) works, after patching cl-tls to remove some missing type specifiers
<_death> no, that vector represents the certificate in DER format
<Josh_2> Man this kinda suck :joy:
Bike has quit [Quit: Connection closed]
<Josh_2> Hey that worked! One piece of the puzzle complete I guess :joy:
<_death> after x509-decode, you get an object that you can inspect.. in a tbs-certificate instance, there's subject-pki slot, which contains a plist with a :subject-public-key indicator that contains a plist with the public exponent and modulus
<_death> the modulus is already represented as a number, which is good as that's what ironclad wants
ahc has quit [Quit: Client closed]
<Josh_2> Alrighty! I now have my ironclad:rsa-public-key
<_death> now, RSA also has different signature schemes.. probably old PKCS#1, but could also be PSS
<Josh_2> One sec lemme see if I can find out
<_death> anyway, you can probably figure things out from here.. ;)
<Josh_2> probably not
<Josh_2> xD
<_death> bruteforce works in crypto programming, if not crypto itself ;)
<Josh_2> paypal docs dont say anything about pss or pkcs...
<Josh_2> oooo
<Josh_2> Its pkcs1 from some example code I can see on stackoverflow
<_death> so that's the default for ironclad:verify-signature
Oddity has joined #commonlisp
lisp123 has quit [Quit: Leaving...]
<_death> hopefully your work will result in some love to cl-tls.. it has some potential for lisp, dunno why the author stopped working on it
<_death> note that if you're dealing with certificates, you also need to check that they are not expired, or possibly revoked
<Josh_2> Well I'd hope they aren't considering its paypal
<Josh_2> Just gonna run on trust for now anyway
<Josh_2> Still not got my verification working
<_death> they have an expiration date
<_death> and cl-tls has ocsp code as well
<Josh_2> each request they send a new url to get the signature from
<_death> yeah, but you still need to check that
<Josh_2> :(
<_death> maybe not ocsp
<_death> but the date, yeah
<Josh_2> lemme get the verification working then I'll do that
<_death> also you need to make sure that the cert is signed by the a trusted root
<_death> (paypal)
<_death> crypto is hard ;)
<Josh_2> Yeh
<Josh_2> I would have just let paypal do it, they have an api call that lets you verify their webhooks
<Josh_2> but that wasn't working as I complained about earlier
<_death> are there no paypal lisp libs already?
<Josh_2> There is the one I made
<Josh_2> And ones that are really old
<_death> I see
<Josh_2> I'm gonna put this verification into my paypal wrapper (when it works :( )
<Josh_2> The verification that is
cage has quit [Quit: rcirc on GNU Emacs 27.1]
Krystof has joined #commonlisp
Bike has joined #commonlisp
<Josh_2> Well I have gotten it to return nil xD
reggie_ has joined #commonlisp
reggie_ has quit [Remote host closed the connection]
<Josh_2> Haven't gotten it to return a t yet :(
<_death> the arguments are in the wrong order
<Josh_2> oof
<Josh_2> The arguments to verify?
<_death> oh, I was looking at %verify-message
<Josh_2> I'm not sure if I'm calculating the CRC correcting
<Josh_2> correctly*. I know its meant to be an integer but does the ironclad built in function return the correct result idk
<_death> do you not have some test vectors
<Josh_2> I do
<Josh_2> I have a webhook from paypal
<Josh_2> but no I didn't test the crc
<Josh_2> lemme go see
<Josh_2> Well I put abcde into an online crc32 generator and got a different result with mine
<Josh_2> uff
<_death> there are several variants of crc.. but usually when it's finalized, it's xored with #xffffffff
<Josh_2> He is looping over each by and and i have no idea
<Josh_2> This is such a pita I just wanna take paypal payments :joy:
<_death> looks like you want ~8,'0X for the crc
<_death> well, in lowercase
<_death> (format nil "~(~8,'0X~)" #xdeadbeef)
waleee has joined #commonlisp
<Josh_2> Hmm I dont think I did it right
<Josh_2> Man I really suck at this stuff
<Josh_2> I can use ironclad to return a hex string
<_death> yeah
Krystof has quit [Ping timeout: 260 seconds]
<_death> it might be little/big endian confusion
<Josh_2> That gives me the same result as from the online calculator
<Josh_2> but I dont know whether i want the hex or the decimal appended to my 'expected signature'
waleee has quit [Ping timeout: 245 seconds]
<_death> the C# code has foreach (byte b in crc32.ComputeHash(arrayOfBytes)) hash += b.ToString("x2").ToLower();
<_death>
<Josh_2> my word, that C# code uses 'to lower' :(
<Josh_2> I dont know what that means
<Josh_2> Everything is like an ELI5 for me right now :joy:
<Josh_2> I need to go back to preschool
<_death> it means to lowercase.. basically the output you get from ironclad:byte-array-to-hex-string
<Josh_2> Ah
<Josh_2> so I already have it (yes I got the to lower part, I meant what that meant in regards to my result)
<Josh_2> So now I assume I am computing the correct crc, I wonder what else is wrong then
<_death> it also needs pkcs1 padding
<Josh_2> :facepalm:
<Josh_2> Isn't that the default for verify?
mason has left #commonlisp [#commonlisp]
<Josh_2> Ah, says in the ironclad manual that pkcs1 has to be implemented by the user
<Josh_2> (at this time)
pve has quit [Quit: leaving]
<Josh_2> cl-tls has cl-tls:rsassa-pkcs1.5-verify
<_death> yeh.. maybe cl-tls will do
<Josh_2> So now I can get rid of using ironclads signature verify (and everything that went along with generating the pubkey) and instead use the cl-tls ?
<_death> first check that it works
<Josh_2> Hmm I think its actually using ironclads
<Josh_2> Well it returns nil when I use that
<Josh_2> I have to go now, shame its not sorted :( I really really appreciate all of your help _death there is about 0% chance I would have been able to get this far on my own
<_death> no sweat.. don't give up, it'll work out ;)
peterhil has quit [Ping timeout: 265 seconds]
McParen has left #commonlisp [#commonlisp]
waleee has joined #commonlisp
mfiano has quit [Remote host closed the connection]
mfiano has joined #commonlisp
hobo has quit [Ping timeout: 264 seconds]
hobo has joined #commonlisp
waleee has quit [Ping timeout: 268 seconds]
hobo has quit [Ping timeout: 260 seconds]
varjag has quit [Ping timeout: 246 seconds]
peterhil has joined #commonlisp
ahc85 has quit [Quit: Client closed]
cosimone has quit [Quit: ERC (IRC client for Emacs 27.1)]
Posterdati has quit [Ping timeout: 245 seconds]
Devon has quit [Ping timeout: 246 seconds]
hobo has joined #commonlisp
mfiano has quit [Remote host closed the connection]
mfiano has joined #commonlisp
peterhil has quit [Ping timeout: 260 seconds]
Posterdati has joined #commonlisp
hobo has quit [Ping timeout: 260 seconds]
peterhil has joined #commonlisp
hobo has joined #commonlisp
tyson2 has joined #commonlisp
Jach has quit [Quit: Leaving.]
X-Scale` has joined #commonlisp
X-Scale has quit [Ping timeout: 264 seconds]
X-Scale` is now known as X-Scale
Bike has quit [Quit: Connection closed]
Jach has joined #commonlisp
waleee has joined #commonlisp
rgherdt has quit [Ping timeout: 260 seconds]
mfiano has quit [Remote host closed the connection]
mfiano has joined #commonlisp
waleee has quit [Ping timeout: 264 seconds]
taiju has quit [Ping timeout: 246 seconds]
hendursaga has quit [Ping timeout: 276 seconds]