freenode/#lisp - IRC Chatlog
Search
8:59:31
solene
hello, I face an issue and I can't find a solution so here I am :) I reduced the whole thing to a few lines of code to try to figure out what's happening. when I read a file containing characters like ↓ , when I save that string into a file, sbcl adds 0x0 characters for each one found, and ecl adds 0x20 characters. I made an example easy to run here https://pastebin.com/pL0HiyGW
9:01:26
solene
sure no-defun-allowed , I didn't try it, only found :external-format :utf-8 but didn't help.
9:05:09
solene
I have this bug since years, I didn't notice it with ecl because spaces in an xml file wasn't an issue (but I'm not happy they are there) but when I switched to sbcl, adding 0x0 characters did break everything of course so I spotted that behavior.
9:05:28
no-defun-allowed
solene: I think that FILE-LENGTH is counting the number of bytes, not characters, in the file.
9:06:18
no-defun-allowed
But then READ-SEQUENCE reads in characters, leaving a gap at the end of the string.
9:06:46
no-defun-allowed
phoe: Compare the results of (make-string 20) on SBCL and ECL. SBCL fills it with (code-char 0), and ECL fills with spaces.
9:08:27
phoe
(coerce (load-file "test.txt") 'list) ;=> (#\DOWNWARDS_ARROW #\RIGHTWARDS_ARROW #\Newline #\Nul #\Nul #\Nul #\Nul)
9:08:34
no-defun-allowed
In this case, I would have expected FILE-LENGTH to count characters, but I think that would require decoding the file.
9:09:36
solene
I'd prefer to avoid external libraries, I use this in a 200 lines lisp program. But if this is the only way
9:10:12
phoe
https://gitlab.common-lisp.net/alexandria/alexandria/-/blob/master/alexandria-1/io.lisp#L53-71
9:18:49
solene
phoe, I switched to using alexandria from quicklisp. Less work and I guess I'll be able to live with this :) thank you very much phoe and no-defun-allowed
9:51:56
phoe
Only partially Lisp-related question: is it possible to get something equivalent to (lambda () (go :foo)) or (lambda () (return-from :bar 42)) in some of the currently-popular programming languages? We assume that these lambdas were established in suitable lexical environments within proper TAGBODY/BLOCK forms.
9:52:40
phoe
I'm thinking about this since I'm currently chewing on one comment related to my book that touches this topic.
9:55:27
phoe
I see, so instead of invoking a function that came from the provided lexical environment, one can emulate TAGBODY/BLOCK using an try-catch form, and transfer control via throwing that exception.
10:04:32
phoe
_death: I actually started re-reading that article moments before you posted it now; it was posted recently
10:05:17
_death
another good resource is the book Lisp in Small Pieces, which has a chapter about throw/catch
10:08:38
_death
in metacircular, the catch macro in catch/throw emulated by tagbody/go is missing a parenthesis :x
11:08:50
jackdaniel
speaking of terms, any volunteers for proofreading and testing the terminal access tutorial?
11:53:51
jdz
jackdaniel: If it's about moving cursor around and switching terminal to non-canonical mode count me in.
11:55:41
jdz
Besides the one ECL issue I already reported I'm having another one with receiving SIGWINCH.
12:20:00
adlai
ACTION tried reading all of `man 1 kill`, it is worse than eating a whole page of lsd
12:20:46
adlai
in case you are unfamiliar with the latter metaphor, it does not fit within a metabolic segment, and is thus slang for "way too much"
12:23:49
phoe
I kind of disbelieve that I have an urge to ask "what is a metabolic segment" in context of discussing LSD on #lisp
12:32:45
jackdaniel
jdz: please report it of course. and yes, it is about moving cursor and switching terminal to non-canonical mode
14:10:22
theseb
Is it necessary to sometimes explicitly use eval in your code? I've been racking my brain on little projects and it seems sometimes you *must* use an eval in your code?
14:12:00
theseb
Bike: i'm writing a for loop ...i can do it as a macro or function...in both cases i can't see how to get everything w/o eval
14:12:33
Josh_2
in the one case where I could have used eval, instead I just compiled the source code and called the function
14:12:34
Bike
assuming you mean something like C for, that executes some code in a loop until a condition is met.
14:12:52
theseb
Bike: i create macro that allows....(for i (3 5 6) ....) that executes ..... for i = 3, 5, 6
14:13:20
theseb
Bike: problem is sometimes I need to do (for i foo ...) where foo evaluates to a list
14:13:40
Bike
You don't need eval for that either, and you should decide whether your macro evaluates the list or not.
14:14:26
Bike
e.g., if you have (for x (get-list y z) ...), is that supposed to be a list of three elements GET-LIST, X, Z, or is it supposed to call the GET-LIST function?
14:14:56
theseb
Bike: but if i do that using a regular function...I need eval to actually eval the .... !!! AHHHH!!
14:15:29
Bike
or the evaluated version, (defmacro for (var list &body body) `(loop for ,var in ,list do (progn ,@body)))
14:16:16
phoe
once you solve that problem, please just quote your lists and use (for i '(3 5 6) ...)
14:17:49
Bike
the question is whether (gethash x y) is evaluated, or treated as a list of three symbols
14:18:15
Bike
this is part of the semantics of your macro, and unrelated to using eval or not to implement it
14:18:33
Bike
but just to emphasize, either way, you definitely don't need to use the eval function.
14:19:05
Bike
FOR is a macro. It can just expand into code that involves evaluating the form. You don't need to call eval yourself.
14:19:06
phoe
theseb: (let ((y (make-hash-table)) (x :some-key)) (setf (gethash x y) '(1 2 3 4 5)) (for i (gethash x y) (print i)))
14:19:41
theseb
Bike: i'll need to define for as a regular function so that it evaluates the arguments...hence...i would do (for 'i (gethash x y) '...)
14:20:47
Bike
You need the form evaluated at run time, not at macroexpansion time, which is what you'd get with eval.
14:22:05
Bike
If you don't want to use LOOP, you could define it in terms of tagbody, though it might be too long for me to write as one line in chat.
14:22:07
theseb
Bike: (defmacro for (var list &body body) `(loop for ,var in ,list do (progn ,@body)))
14:22:38
phoe
also, you *never* need eval unless you really, really need it. most of the use cases can be achieved via closures or macroexpansions
14:23:12
phoe
eval usually comes into play when you need to be able to get commands from the programmer, which means that you have a REPL of some sort.
14:23:30
Bike
it's also important to understand that eval doesn't know about the lexical environment it's called in, so in this case you actually cannot use eval to achieve this, given that X and Y are lexical variables.
14:23:40
phoe
otherwise, for purely programmatic means of processing code, you do not really ever need it.
14:28:22
theseb
phoe: is there some general principle here that the magic is in using multiple levels of macros?
14:29:27
theseb
just wondering if that was the trick...regardless...i'll test it and think more today
14:29:39
Bike
and no, like i said, you can do this using tagbody, which is a special operator rather than a macro.
14:30:08
TMA
theseb: the magic is that the macro you write can produce any code you could have written instead. that code might or might not contain references to other macros (or even to the same macro)
14:30:44
Bike
yeah, try writing out how you'd do (for ...) if there is no for macro, and then have the for macro expand into that kind of code.
14:31:23
theseb
Bike: does your brain ever hurt trying to keep in your head which args should be quoted or not?
14:33:06
phoe
(defmacro for (variable value &rest body) `(block nil (let (,variable (list ,value)) (tagbody :check (when (null list) (go :exit)) :iterate (setf ,variable (pop list)) ,@body (go :check) :exit))))
14:34:54
phoe
TMA: (defmacro for (variable value &rest body) `(block nil (let (,variable (list ,value)) (tagbody :check (if (null list) (go :exit)) :iterate (setq ,variable (first list)) (setq list (cdr list)) ,@body (go :check) :exit))))
14:39:00
Bike
the point isn't the macros, anyway, it's that you can see that the macroexpansion does not evaluate the VARIABLE form, but does evaluate the VALUE form, based on their positions in the LET
14:39:54
phoe
or, in other words, the macroexpansion doesn't really evaluate anything, but it may choose what to quote and what not to quote
14:40:09
phoe
so that in the resulting macroexpansion there's stuff like 'I which, after normal evaluation, produces the symbol I
14:40:38
phoe
and there might also be stuff like (GETHASH X Y) which, after normal evaluation, produces the value associated with key X in hashtable Y
14:49:34
phoe
therefore people who write code that abuses EVAL have little feedback from the system to fix it so it does not use EVAL
14:50:08
phoe
and that, in turn, is non-trivial unless you actually reach out to other lispers or get a good code review which implies reaching out to other lispers
14:52:27
phoe
I gotta make a lisp meme sometimes that follows the greentext >learns about quote >notices that quote is the operator that allows stuff to be passed to eval >uses eval everywhere >"damn lisp is so slow"
14:58:18
theseb
Bike: just curious about your (defmacro for (var list &body body) `(loop for ,var in ,list do (progn ,@body)))....did it *have* to be a macro....could you get away with something like (defun for (var list body) (loop for var in list do (progn ???))) and later do (for 'i '(3 4 5) '(print i)) somehow?
14:59:42
Bike
I mean I guess you could do something stupid like (loop for x in list do (eval `(let ((,var ',x)) ,body)))
15:00:26
theseb
Bike: i wanted to see if an eval was necessary ;)...and you seemed to suggest it was ;)
15:00:47
Bike
Yes, if you want code to be evaluated at runtime you need to use EVAL (or COMPILE or something), like i said before
15:01:01
Bike
In this case you are defining that the FOR function must actually evaluate code, so that's natural
15:02:50
theseb
Bike: i'm not sure how you know the answers so fast...it takes me a while to reason thru all this
15:05:47
phoe
one comes after the other, with the exception of macroexpansion time which is usually a part of compilation time
15:07:00
phoe
and there's plenty to do in earlier times, since each of them has its own separate macro system
16:32:46
jmercouris
is it incorrect to say filename = (format nil "~a.~a" (pathname-name path-x) (pathname-type path-x)) ?
16:33:06
jmercouris
given some path, how to get file name? #P"/opt/local/lib/libz.dylib" trying to get "libz.dylib" as as tring, so I am doing the above
16:39:42
_death
the standard namestring functions are basically useless.. you want a native-namestring
17:37:09
yottabyte
I'm using https://www.cliki.net/html-encode but none of the functions listed seem to encode the space character to %20. is this perhaps the wrong library to use?
17:43:18
Bike
when a funcallable instance is updated for a different class, does the copy of the instance passed to update-instance-for-different-class still have the funcallable instance function?
17:44:15
Bike
i mean, it says you can't change-class a generic function, but that doesn't cover everything
17:45:43
phoe
but then again, an implementation might as well state that changing the fin's class, for whatever reason, invalidates the previous function
17:45:47
Bike
well, no, but the user method is passed a copy of the instance, and hypothetically they could call it
17:52:49
phoe
I could bet a few bucks that that some implementors might not even be aware that this might be a question
17:53:14
Bike
i guess you could just set the instance function to be the instance. that works, right? setting the instance function to be an instance?
17:55:32
phoe
I assume that if the function then modifies the original's slots, that's somehow accounted for by the programmer
17:55:50
phoe
because this means that when you funcall the instance, you then funcall the instance, which means that you funcall the instance
17:57:51
phoe
if the fin is implemented in a way where there's some sort of trampoline that jumps to the actual cl:function object, then it may jump to itself and we have an infinite loop