freenode/#lisp - IRC Chatlog
Search
8:46:08
myrmidon
Hi! I'm trying to make a macro produce a backtick list with some ,@(when ...) forms in it, but all I can get is ,(when ...) forms: https://ptpb.pw/PVsQ/lisp -- any advice?
8:54:39
no-defun-allowed
double backquotes aren't my strong point but i think you'd need to backquote-splice twice
8:59:01
jackdaniel
you may splice it shallow or deep and even CL implementations are not consistent here
9:00:49
jackdaniel
if you are interested in details, check out this thread: http://web.archive.org/web/20130622010232/http://sourceforge.net/p/ecls/bugs/251/
9:04:59
aeth
At this point I'd just use helper functions or at least move most of it to a let at the top to try to make it a little readable
9:06:24
aeth
When the macro gets complicated I tend to do (let ((some-piece `(foo ,(bar 42) baz)) (another-piece ...)) ...)
9:06:40
aeth
At the very least, even if it doesn't help too much with readability, you avoid most ,,s that way
9:08:26
aeth
Whether it makes more sense in a helper function or a let at the top (or both, where the let at the top is just calling a function) is hard to say, of course.
9:10:09
myrmidon
,@(append ,@(...)) is working but I think you're right it's a bit messy, i'll try to rework it
9:39:09
makomo
jackdaniel: i've read the thread you linked but i don't get how ``(,@,@foo) corresponds to the `,@foo case which is undefined
9:46:38
makomo
jackdaniel: right, but that's kinda "handwavy", as it's not how it is formally defined, no?
9:46:53
jackdaniel
I don't have time to discuss it right now, sorry. I have said everything I had to say.
9:47:38
makomo
jackdaniel: ah, ok. i'm just interested in interpreting the formal rules that the spec gives fpr backquote and figuring out exactly where it fails
9:47:55
makomo
jackdaniel: if you come up with an idea, let me know (and i'll do the same if i figure it out)
9:48:17
jackdaniel
I think that all there is about ,@,@ is covered in this thread, so I find hard to add anything to it
9:49:39
makomo
jackdaniel: ahhh never mind, i see it now. you have to do the expansion by hand using the formal rules to see it
10:07:42
makomo
jackdaniel: hm, i said that too quickly, without actually doing it by hand but just thinking that it would surely show up
10:08:31
makomo
jackdaniel: however, regarding your ",@foo is defined, if foo is a list", take this example "(let ((var 10)) `(,@var))"
10:09:58
makomo
afaict, that is a valid backquote template according to the formal rules, because, even though the final forms are implementation-defined, the semantics still have to match with the forms that are used in the formal rules
10:11:00
makomo
using the formal rules, the above expands into "(let ((var 10)) (append var))" which is valid, because APPEND takes any object as its last argument
10:12:03
makomo
jackdaniel: using these rules: http://www.lispworks.com/documentation/lw70/CLHS/Body/02_df.htm
10:12:30
makomo
the bullet "* `(x1 x2 x3 ... xn . atom) may be interpreted to mean (append [ x1] [ x2] [ x3] ... [ xn] (quote atom)) (...)"
10:14:17
makomo
the spec says "`#(x1 x2 x3 ... xn) may be interpreted to mean (apply #'vector `(x1 x2 x3 ... xn))"
10:14:23
jackdaniel
I don't see direct implication on `(,@var) -> (append var), in fact evaluating `(,@3) gives me three, not (append 3)
10:14:50
makomo
jackdaniel: evaluating, yes, but i was talking about the "expansion", i.e. what the backquote template is read in (using the forms given in the standard)
10:15:26
jackdaniel
OK, as I said I have no time to dive into spec. it is not that I disagree or anything, I've just pointed out that ,@,@ is undefined since I saw it
10:15:55
jackdaniel
(I know that I'm not physically forced to discuss that, but all these highlights certainly make me feel so)
10:16:54
makomo
jackdaniel: sorry if i was being a bother, i won't ping you anymore :-). but yeah, if you get the time in the future, let me know
10:17:34
jackdaniel
I want to point out, that I'm not also especially interested in discussing such things unless it is a mean towards implementing something correctly
10:17:57
jackdaniel
I can spend such time on other thigns (also beneficial to CL community), like fixing bugs
10:19:10
makomo
jackdaniel: sure, i understand. s/if you get the time/if you feel like discussing it/ is what i meant :-)
11:35:15
pjb
makomo: on 2.4.6, 4th star (*), [,@form] is interpreted as form. `(foo `(x1 ,@,@form x3)) --> `(foo (x1 ,@form x3)) ; seems legit to me. (let ((form '((1) (2) (3)))) `(foo `(x1 ,@,@form x3))) #| --> (foo (list* 'x1 (append (1) (2) (3) '(x3)))) |#
11:36:37
makomo
pjb: can you perform the expansion bit by bit and show the intermediate results? the thread that jackdaniel linked says that the behavior of ,@,@ is undefined
11:37:06
pjb
makomo: I don't think it's undefined. clhs 2.4.6 has a rule for it, which means that: `(foo `(x1 ,@,@form x3)) --> `(foo (x1 ,@form x3))
11:37:21
pjb
therefore ccl evaluating successfully this form: (let ((form '((1) (2) (3)))) `(foo `(x1 ,@,@form x3))) #| --> (foo (list* 'x1 (append (1) (2) (3) '(x3)))) |#
11:37:42
pjb
seems to confirm that there's a meaning for it, and given it's specified, it seems to be conforming.
11:37:51
makomo
pjb: you can't just collapse it like it. i think you're reading it out of context -- read all of the rules for `(...)
11:38:15
makomo
this one "* `(x1 x2 x3 ... xn . atom) may be interpreted to mean(append [ x1] [ x2] [ x3] ... [ xn] (quote atom))"
11:39:32
makomo
therefore, ``(hello ,@,@there) == `(append (list `hello) ,@there) == `(append (list 'hello) ,@there) == `(append (list `append) (list `(list 'hello) there), no?
11:39:59
makomo
but that's not the result i expected. i expected a `,@foo to show up, which is undefined by bullet 3
11:40:04
pjb
(quote `(foo `(x1 ,@,@form x3))) #| --> (list* 'foo (list (list* 'list* (list* ''x1 (list (list* 'append (append form '('(x3))))))))) |#
11:42:50
makomo
but hm, yeah, i guess it might be wrong, because i can't see what's undefined about it (**using the formal rules!**)
11:45:46
makomo
i do it in small steps, fully expanding all the inner ` before going onto the outer `
11:46:42
makomo
that's how the algorithm works anyway, except it does it recursively. because we're humans, i prefer to do it iteratively. the result is the same, as the innermost backquote is always fully expanded before the outermost one
12:05:48
pjb
(let ((there '((list :x 1) (list :y 2)))) ``(hello ,@,@there)) #| --> (list* 'hello (list :x 1) (list :y 2)) |#
12:06:44
pjb
(list* a d) = (cons a d) (list* a1 a2 a3 .. an d) = (cons a1 (cons a2 (cons a3 … (cons an d))))
12:08:49
pjb
(APPEND (LIST 'HELLO) (LIST :X 1) (LIST :Y 2)) #| --> (hello :x 1 :y 2) |# same result.
12:09:22
pjb
(eval (let ((there '((list :x 1) (list :y 2)))) ``(hello ,@,@there))) #| --> (hello (:x 1) :y 2) |#
12:09:54
pjb
(eval (let ((there '((list :x 1) (list :y 2)))) ``(hello ,@,@there foo))) #| --> (hello :x 1 :y 2 foo) |#
12:10:01
pjb
(let ((there '((list :x 1) (list :y 2)))) ``(hello ,@,@there foo)) #| --> (list* 'hello (append (list :x 1) (list :y 2) '(foo))) |#
12:10:28
pjb
(let ((there '((list :x 1) (list :y 2)))) ``(hello ,@,@there)) #| --> (list* 'hello (list :x 1) (list :y 2)) |#
12:11:15
pjb
(let ((there '((list :x 1) (list :y 2) nil))) ``(hello ,@,@there)) #| --> (list* 'hello (list :x 1) (list :y 2) nil)|#
12:12:24
pjb
Yes, because (append [ x1] [ x2] [ x3] ... [ xn] (quote atom)) means that xn is not the last argument to append. If you have a proper list, then atom is nil.
12:12:54
pjb
So (let ((there '((list :x 1) (list :y 2)))) ``(hello ,@,@there)) should be the same as (let ((there '((list :x 1) (list :y 2) nil))) ``(hello ,@,@there))
12:13:07
pjb
(values (eval (let ((there '((list :x 1) (list :y 2)))) ``(hello ,@,@there))) (eval (let ((there '((list :x 1) (list :y 2) nil))) ``(hello ,@,@there)))) #| --> (hello (:x 1) :y 2) ; (hello (:x 1) (:y 2)) |#
12:13:55
makomo
i've been forgetting about that (quote atom) (or rather (quote nil)) at the end this whole time
12:23:32
pjb
Either formally, or fundamentaly like in this case. Formally in the case of prog2, implementations don't do what's written but what was meant.
12:26:22
flip214
the first has a CDR of NIL, the second has a _list_element_ of NIL (with a CDR of NIL, too)
12:26:44
makomo
flip214: i'm only following the rules given by http://www.lispworks.com/documentation/HyperSpec/Body/02_df.htm
12:26:56
flip214
and my experiments some time ago showed me that ,@,@ is most often wrong - ,',@ is sane ;)
12:27:47
flip214
pjb: makomo: well, AFAIK the CLHS isn't the final standard - and even if it were, it might contain errors.
12:28:17
makomo
flip214: well, that's just speculation i guess. these formal rules have been described by Steele as well
12:28:51
makomo
i agree the standard isn't pefect, but this section in particular being wrong seems highly unlikely to me
12:30:32
flip214
and the first form replaces the last CDR by NIL (which it already was), and so returns the same thing. got ya.
12:39:52
makomo
pjb: ah nice, i was just about to ask whether you were going to open another issue for the `(,@var) thing
12:41:53
makomo
if ccl goes with the changes then i might do it, because i'll have more evidence to point to
12:47:19
makomo
"first it has all the bugs straightened out, including dark corner cases (some implementations still get the simple ``(foo ,@,@bar) wrong);"
13:11:18
russellw
I don't suppose there is anything like a way to tell loop to do one more iteration? Specifically, I'm trying to implement a read-line function as something along the lines of (loop until(eql(peek-char #\newline)) collect(read-char)) but then that doesn't collect the actual newline
13:17:04
makomo
`(,@foo) is technically incorrect but fare-quasiquote accepts it by default in the name of interoperability and consensus. there's a feature you can use to make it signal an error
13:18:08
makomo
jackdaniel: just to let you know: we concluded that ,@,@var is well-defined defined but that `(,@var) is not (contrary to what i said the first time -- i forgot the ". nil")
14:12:32
jackdaniel
and despite reading whole thread I didn't change my mind, but I'm not motivated enough to defend that claim
14:17:21
jackdaniel
it is because a) it is the last argument, b) all preceding lists are null (and dragons and whatever), because it is an empty cave of knights ;-)
14:31:37
makomo
jackdaniel: yeah, true, and that is why `(,@10) => 10 is incorrect. `(,@foo) actually reduces to `(,@foo . nil) which then expands into (append foo 'nil)
14:31:57
makomo
since foo is 10, that APPEND call should fail, but it seems like most implementations have broken backquote simplifiers
14:38:17
beach
The SICL implementation of the macro ECLECTOR.READER:QUASIQUOTE expands the form returned by Eclector to (APPEND 10 'NIL)
14:38:32
jackdaniel
"If a comma is immediately followed by an at-sign, then the form following the at-sign is evaluate" – that means that defined behavior applies only to at-signs followed by forms. and I'm not diving into that discussion any further, I kind of regret that I said anything about ,@,@ earlier. If I'm wrong - so be it.
14:41:54
makomo
jackdaniel: yes, right, but that applies to a single level of backquote. n nested backquotes require n evaluations to fully process. the spec is at all times talking about a single level of quotation, and the rest have to be handled recursively
14:43:32
jackdaniel
does anyone know dejavu ttf fonts which have vmtx table defined? (for testing font renderer)
14:44:33
makomo
beach: and what about (let ((there '((list :x 1) (list :y 2)))) ``(hello ,@,@there))?
14:45:05
makomo
woop,s you'll have to evaluate the result of that once again to get the final result
14:48:19
beach
It's interesting how I can evaluate SICL code even though SICL doesn't exist, isn't it? :)
14:51:41
makomo
beach: speaking of bootstrapping. CL has various functions which are primitives and cannot really be implemented by the user. stuff such as CAR, CDR, APPLY, +, -, etc. now, thinking about meta-circular interpreters, would it ever be possible to write an interpreter for a language L in L, but without relying on L's primitives?
14:53:31
Bike
you can implement lisp in lisp without using host lisp structures to represent client lisp structures.
14:53:34
makomo
ggole: hm, but let's say we take + for example. how would you avoid using + within the interpreter itself?
14:53:47
russellw
makomo, sure, you could reimplement numbers using church numerals or whatever. It's just that it would be very slow
14:54:05
makomo
russellw: aha, that's what came to my mind to, but wouldn't you still have to rely on "incrementing" somewhere?
14:55:02
Bike
the client would only be able to access them as client numbers, though. non porous abstraction
14:55:13
ggole
And within the implementation of object-language primitives, you could use + (if the semantics were correct)
14:56:02
beach
makomo: You can't avoid using host functions for the interpreter itself. You have to have access to the computation machinery.
14:56:05
Bike
einstein thought about the dude with a flashlight because ehe was wondering about relativity
14:56:21
makomo
Bike: yeah, i'm trying to sort out the meaning of "meta-circular" from the various subtly conflicting definitions i've read
14:56:24
ggole
Programming without certain primitives is possible up to a point, but you need to encode your logic into something in the host language
14:56:47
makomo
ggole: mhm, true, but i just want to avoid using the exact same primitive to implement the feature of the object language
14:57:57
Bike
i mean the client lisp will be unable to treat church numerals except as numbers. it won't be able to FUNCALL them or anything.
14:58:26
makomo
Bike: and as another example, let's take closures. these would also be implementable without using host's closure, but using a separate "hand-written" data structure, right?
14:59:08
beach
makomo: You would have a representation of a function as a structure containing "code" and "environment".
14:59:13
Bike
well, it might use host closures internally, depending on how the implementation works, but it doesn't have to BE a host closure
14:59:49
makomo
ggole: right, true. in this case i'm using L to implement L (L being Lisp in this example), but of course, you could implement Lisp in assembler and assembler obviously doesn't have closures
15:00:13
ggole
The object language should not be able to tell the difference (except in operational senses such as time taken)
15:00:38
Bike
if you can implement lisp in assembler you're not using lisp functions, so there's no way it would be required to use lisp functions.
15:01:34
makomo
i mean, wouldn't using assembler's INC or ADD (assuming some common assembler) qualify as circular? i'm not sure
15:04:27
makomo
we've talked about this before, what i really want to do is figure out why the name is "meta-circular" and not just "circular". i've come to the conclusion that (1) it's "meta" because it's L implementing L and (2) it's "circular" because you're reusing the host's primitives to implement the object's primitives
15:04:55
makomo
i could throw away the circularity and just have an L implemented in L, a "metainterpreter" i guess
15:05:00
Bike
i hope you realize there's a decent chance it's "metacircular" because a mildly drunk programmer thought it sounded cooler.
15:05:17
beach
Maybe you are putting too much interpretation into a name that might have been chosen quite arbitrarily.
15:05:44
Bike
"The term itself was coined by John C. Reynolds, and popularized through its use in the book [SICP]" so maybe there's an explanation, i don't remember.
15:06:13
makomo
Bike: sicp does mention it (of course), but it's like there's an implicit assumption that the implementation reuses host's primitives
15:06:40
Bike
that's just because it's what sicp is about. it should be obvious it's not required or programming would be impossible.
15:07:03
beach
makomo: I don't think the term is sufficiently well defined to determine whether using host primitives is acceptable.
15:07:09
Bike
as far as i remember, as sicp goes on the host-client link gets more and more distant.
15:07:19
makomo
4.1 says "An evaluator that is written in the same language that it evaluates is said to be metacircular."
15:14:54
makomo
Bike: that paper explicitly mentions the circularity part, "We have coined the word “meta-circular” to indicate the basic character of this interpreter: It defines each feature of the defined language by using the corresponding feature of the defining language."
17:14:27
jcowan
can anyone talk about practical examples of degenerate arrays, either of rank 0 or of no elements?
17:25:15
jcowan
I was actually thinking of multidimensional arrays rather than vectors of size 0; I see the application of the latter well enough, as they are a particular instance of empty indexable sequences
17:26:13
ggole
Once you allow empty arrays of rank 1, it would be inconsistent to disallow empty arrays of higher rank.
17:29:25
pjb
jcowan: (aref #0A42) #| --> 42 |# can be used as a generalization of scalar in a context where you are processing arrays.
17:33:44
pjb
yes, http://www.lispworks.com/documentation/HyperSpec/Body/22_c.htm says that format CREATES and returns a string containing the output.
17:35:47
sjl
Yeah, it would have been nice if they had just said "fresh string" in the FORMAT section itself.
17:36:41
pjb
(make-array '(2 2) :initial-contents '((1 2) (3 4))) #| --> #2A((1 2) (3 4)) |# is mutable.
17:37:58
sjl
If by "immutable" you mean "the consequences are undefined if you mutate it" sure, but that's not what jcowan means.
17:49:42
LdBeth
Immutable array is stupid idea, there are bunches of more efficient immutable data structures to use
17:51:24
jcowan
I meant immutable in Henry Baker's sense: an exception is thrown if you try to mutate it.
17:55:52
ggole
In general you need updates to data structures, and copying the whole array is too slow
17:57:07
ggole
For persistent arrays tou can do structure-sharing stuff with wide nodes to do better than that, but that's not 'immutable arrays' in the sense that you seem to mean
17:59:51
jcowan
"Immutable vectors of non-characters can be extremely useful as lookup tables, which can be passed in toto without worrying about the callee side-effecting the table." --HB
18:02:43
jcowan
immutable objects are also good in distributed computing, which is one of HB's central concerns.
18:10:58
jcowan
I tried to remove mutable strings from Scheme, where strings are sui generis (not arrays), but failed to convince the committee to break the IEEE standard
18:12:55
pjb
Nothing prevents an implementation to provide them. The verbiage of the specifications clearly allows it.
18:13:30
void_pointer
One of the hard things is that assuming one has managed to get all of one's data into a valid state in the first place, is keeping it from becoming invalid. I've had times where an array was the best structure for something but it was something that should not change at all after creation (it was intercoupled with some other things that shouldn't change).
18:13:40
heisig
Truly immutable data structures always sound nice on paper - until you have an application where performance and storage matter a lot.
18:16:35
void_pointer
It is a fairly common situation to have 2D or 3D arrays that should never change once initialized when doing various scientific and engineering simulations. Though to be fair, it isn't exactly common for the people doing such simulations to worry about this or many other problems, for better or worse.
18:21:30
_death
or (defmethod (setf gref) ((array immutable-array) &rest subscripts) (thats-a-no-no))
18:23:13
void_pointer
Or if you can control where it gets stored in memory and have the right permissions, just put it in some pages of memory by itself and then set those pages to read-only so that a fault is raised any time there is a write to the pages assuming you have a processor that supports that.
18:24:16
_death
sure.. and how useful is this feature in practice? in Lisp, we usually document whether the function is destructive or not
18:26:48
void_pointer
It would depend on how mission critical whatever the code is doing is. I don't think common lisp is used for very many mission critical things where great lengths should be gone to to make sure that an invalid state cannot be entered and/or it at least fails gracefully.
18:28:40
void_pointer
You know, an interesting question. Is anybody doing mission critical stuff with lisps these days? I sometimes wonder
18:29:29
_death
void_pointer: language features are often severely overrated when it comes to "mission critical" code.. in practice, it's process and the environment external to the system that matters there
18:31:06
void_pointer
_death: that makes sense. One tool in the toolchest among many. Insufficient by itself
18:35:04
_death
a language isn't any good if the implementation's quality is unknown.. so code has to be written with full knowledge of the latter
18:36:25
_death
but the processes involve actual effort into testing, designing with redundancy and killswitches in mind
18:37:59
void_pointer
Yes, and ideally plain old simple electronic and mechancial failsafes if applicable.
18:49:48
wiselord
hey! Please help me, i need an example for condition with auto-restart for the case: i run function (startn-fn () (ProcessingLoop () ... (getFromWeb ...) )), getFromWeb calls drakma:http-request, and if drakma:http-request (in fuction getFromWeb) return error (usocket:ns-try-again-condition) - i need atomatically restart (restartPL () ...). For manual restart i use code (start-fn () (restart-case
18:51:39
shka_
wiselord: well, ok, try that http://www.gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html
18:52:36
shka_
*handler-bind section explains how to establish restart and invoke-restart with examples included
18:54:27
wiselord
but examples in book for local exceptions, and in my case the signal comes from the usocket package
19:01:08
jcowan
Note that lambdas are mutable or immutable according to whether a set! modifying variables local to the lambda is lexically apparent or not