IRC channel logs

2021-06-24.log

back to list of logs

<dsmith>!seen
<dsmith>!since
<sneek>I've been running for 4 days
<apteryx>Hello Guilers! I'm trying to define a 'define-with-source' macro that'd expand to a procedure definition and also a directive to set the source to the newly defined procedure: https://paste.debian.net/1202204/. For some reason the 'set-procedure-property!' doesn't work as intended; (procedure-source PROC) returns #f.
<apteryx>hints welcome :-)
<leoprikler>docstring body is weird
<leoprikler>Interestingly it works inside a REPL
<leoprikler>apteryx what happens if you peek the procedure properties directly after setting them inside the syntax?
<apteryx>I think the trick is delaying the set-procedure-property! with eval-when: https://paste.debian.net/1202205/
<apteryx>the above code seems to work
<apteryx>instead of docstring body it could be body body* ... I guess :-)
<leoprikler>hmm
<leoprikler>apteryx: If I put the entire thing into (eval-when (load) ...) and load the compiled go, it also works
<apteryx>I think it's safe to do the define at expansion time, but the set-procedure-property! needs the procedure object to exist, which not being a top level syntax is not guaranteed to be at expansion time, IIUC.
<leoprikler>oh, so you mean it breaks if you have a procedure-local define?
<apteryx>What do you mean by procedure-local define?
<leoprikler>(define (foo ...) (define-with-source (bar ...) ...))
<apteryx>I think the subtlety might have more to do with macros being able to use other top level macros, but not other top level definitions at expand time (see "info '(Guile) Eval When'")
<leoprikler>hmm you mean having the define-with-source in a different file from the expansion?
<apteryx>even locally to the expansion, the proc defined is not syntax itself, so even if it appears at the top level, the syntax being expanded can't refer to it at that time
<apteryx>IIUC, which may not be the case as I need to get some zzz
<apteryx>later :-)
<rlb>wingo: I'm don't yet completely understand the code that was changed, but I wondered if guarding it so that it only operates on EOL, not nil, would still accomplish what was needed. It does appear to fix the problems with lokke:
<rlb> (x (eq? (syntax->datum #'x) '())
<rlb> (values '(quote ()) maps))
<rlb>
<leoprikler>rlb will that still work if you terminate your list with #nil?
<leoprikler>other than that, IIUC syntax-case, match et al have order to them, so if you put your #nil case first, that ought to handle it
<leoprikler>though perhaps the syntax for that might be a little awkward, idk
<dsmith-work>Hey Hi Howdy, Guilers
<taylan>heya
<taylan>leoprikler: I believe the point is not to match #nil, although I haven't followed the full conversation.
<taylan>not sure why one would want to avoid matching it. IMO #nil should work like () in all respects and be equal? to it.
<leoprikler>not equal?, but match '()
<leoprikler>but the thing is you want to detect #nil as #f also in languages like clojure and emacs lisp
<taylan>if #nil doesn't equal '() then the Scheme list (foo) and the Elisp list (foo) can't be equal? to each other, which they probably should
<leoprikler>IOW make (match #f) also match nil?
<taylan>(currently indeed they aren't)
<taylan>match uses equal? semantics, right? to keep transitiveness of equal? I would not make #nil equal? to #f.
<leoprikler>I don't think match uses equal
<taylan>basically what I suggest is to "privilege" '() when it comes to equal?'ing #nil, because I think that's a lot more useful than equal?'ing #f
<leoprikler>instead, it special cases a bunch of stuff
<leoprikler>boolean constants being one thing
<leoprikler>if you specify (match #f) => matches #f and #nil, that's exactly what it does
<taylan>hmm. not sure how to feel about that. I've mostly just thought about this in terms of equality predicates.
<taylan>intuitively I'd say #f shouldn't match #nil because it's neither eqv? nor equal? to it, but I haven't used match much so far
<leoprikler>in that case match shouldn't do the nil either, but obviously it has to
<leoprikler>so match needs something else than equal? semantics
<leoprikler>or good ol' helper predicates
<taylan>IMO #nil should just equal '(), and also match it in match. consistent, and probably most useful and least surprising behavior.
<leoprikler>no
<taylan>why not?
<leoprikler>#nil is not equal to either '() or #f
<leoprikler>it is distinct
<taylan>I know it's currently not, but IMO that's pretty much a bug
<leoprikler>that's not a bug, there is a philosophical difference
<leoprikler>saying nil is the empty list is like saying void is any other data type
<taylan>Elisp nil is the empty list though. if you evaluate () you get nil in Elisp.
<leoprikler>I'd write that as '() ~> nil rather than '() = nil, though
<taylan>I guess one could argue that there is no empty list in Elisp and CL... but I don't see the usefulness of thinking of it in those terms.
<taylan>anyway, philosophy aside, I think Scheme '(foo) should be equal? to Elisp '(foo), and that requires (equal? '() #nil).
<leoprikler>I think I prefer erring on the side of uselessness in that case.
<leoprikler>'() is not "structurally equivalent" to #nil, though
<taylan>well it is if you see it as the empty list, so that's the same philosophical question as before
<leoprikler>comparing lists with equal? is imo weird anyway
<taylan>IMO pragmatism above semantic purity is preferable whenever it won't cause (more) headaches down the line. there's already some headaches #nil will invariably cause, but I think making it equal? to '() will actually reduce them.
<leoprikler>making #f equal to '() will cause more headaches
<taylan>that's not what I'm proposing
<taylan>just making #nil equal to '()
<leoprikler>not making #nil equal to #f is the same headache as the list thing though
<leoprikler>so i really don't get your rationale other than "I like lists", I guess
<taylan>I don't think so. checking boolean equivalence with equal? is probably much rarer than checking structural equivalence of lists with equal?
<taylan>it's basically a guess/prediction, but I'm almost sure that if we inspected all uses of equal? out there, there would be many more cases checking structural equality than Boolean equality
<taylan>structural equality involving lists*
<leoprikler>Even if that is true, I don't think that gives us the right to make some "equalities" more equal than others
<taylan>basically, (equal? '() #nil) => #f means that any use of equal? involving lists will "break" when an Elisp list is involved. OTOH (equal? '() #f) => #f will only "break" when an Elisp #nil intended as a Boolean involved.
<leoprikler>what if you have a procedure, that returns a list, including the empty list on success and #f for failure?
<taylan>we're assuming this is a Scheme procedure, and is called from Scheme, right? in that case you have to check (eq? result #f) anyway because (if result ...) will also break.
<taylan>wait, that's not entirely true...
<taylan>can you explain what the problem with that situation would be?
<leoprikler>the problem can be whatever you want it to be
<leoprikler>of course emacs lisp and clojure interop will not be given, so that's one problem
<leoprikler>there will be more depending on what you decide to do with equal?
<taylan>well it has to be a Scheme procedure (otherwise it can't distinguish between empty-list and false in its return), and when called from Scheme it won't pose any problem. both 'if' and 'equal?' on its result will do the expected thing.
<leoprikler>also, i think '() equal? #nil breaks if as well
<taylan>unless I suppose it just so happens to return #nil when it meant empty list, because an Elisp list got in there somehow... but in that case (equal? '() #nil) and (not (equal? #nil #f)) is exactly what you want.
<leoprikler>ahh, but what if Elisp #f got in there? :P
<taylan>no, 'if' doesn't use equal? in any way
<taylan>Elisp doesn't have #f :D
<leoprikler>What I'm saying is it breaks the semantics of if
<taylan>how so?
<taylan>do the semantics of if say that when (if x 1 2) returns 1, then for every y that's equal? to x, (if y 1 2) must also return 1?
<leoprikler>(if (equal? a b) (equal? (if a 1 0) (if b 1 0)))
<leoprikler>It's at least a headache
<taylan>it certainly is, but remember that currently #nil isn't equal? to #f so we already have that headache :)
<taylan>so from that perspective 'if' is already "broken". (I hadn't realized this until now...)
<leoprikler>it would also break other stuff like and
<leoprikler>(and #nil #t) => #t ;; whut?
<taylan>no, why would that happen? 'and' hopefully relies on 'if' semantics?
<leoprikler>(and '() #t) => #t ;; okay
<leoprikler>breaking if basically means breaking your entire language
<taylan>as I said, 'if' is already broken if you consider that breakage.
<taylan>and somehow Guile Scheme still manages to work :D
<leoprikler>it's not if that's broken, it's your concept of equal?
<taylan>hmm wait, yeah I think my previous assertion was wrong.
<leoprikler>note that elispers expect to match the tails of their lists with if from time to time
<taylan>leoprikler: (if (not (equal? a b)) (not (equal? (if a 1 0) (if b 1 0)))) <- do you think this is accurate? (I'm really not sure)
<leoprikler>no
<taylan>but only because (equal? #nil #f) is false, is that correct?
<taylan>i.e. in a world where #nil didn't exist, it would be accurate?
<leoprikler>(or (not (equal? a b)) (equal? (if a 1 0) (if b 1 0)))
<leoprikler>no
<leoprikler>'a is not equal? to 'b, but both return 1
<taylan>oh, derp
<taylan>ok let me try that again... :D
<taylan>(if (not (equal? a b)) (not (equal? (not a) (not b)))) <- how about this one?
*taylan has gotten way too confused, pulls up a REPL
<leoprikler>hmm, lemme check
<taylan>I think I wrote nonsense again
<leoprikler>it's been a while since i did logic&computability
<taylan>the simple example of 'foo and 'bar defeats that, so yeah that was nonsensical again, sorry
<leoprikler>I posted the true tautology a little earlier, try it: (or (not (equal? a b)) (equal? (if a 1 0) (if b 1 0)))
<taylan>well I'm trying to find a different tautology that already breaks due to #nil, hence proving that Guile Scheme is already "broken" in a similar way that (equal? '() #nil) would "break" if
<taylan>let me put my logic in English first: currently, we already have a pair of values that are both false, but not equal?
<leoprikler>Gödel claims I can't have a proof for this, but I think the way Guile currently works is consistent.
<taylan>hmm, actually no, that doesn't necessarily mean it's broken
<leoprikler>that's not how implications work
<taylan>values that are both true don't have to be equal? so values that are both false don't necessarily have to be equal? either...
<taylan>however, in standard Scheme, values that are both false are equal? because there is only one false value...
<leoprikler>that is true, if you take "only one value for #f" as an axiom, then Guile violates the RnRS
<taylan>in that case I think it's two different layers of "breakage" at least with respect to standard Scheme. the first being, breaking the assumption that two false values are equal? this is already the case. my proposal would add a second layer: that a true and a false value can be equal?.
<taylan>however, I would dispute that this makes the semantics of 'if' broken, because equal? isn't eqv?...
<leoprikler>I would say so
<leoprikler>since eqv? is stricter than equal? we do have (and (eqv? a b) (equal? a b))
<taylan>I don't think anything changes in that respect. (list 'foo) and (list 'foo) are also equal? but not eqv? for instance.
*taylan has to go AFK for ~25 minutes
<leoprikler>sure, but (cons 'foo '()) (cons 'foo #nil) is an even laxer comparison
<leoprikler>you need equal-modulo-nil? for that
<leoprikler>(or list-equal?)
<leoprikler>hmm, that makes me wonder…
<leoprikler>taylan: (if (not (equal? a b)) (not (equal? (not a) (not b)))) <- how about this one? this one at least works for pure booleans, but not much else I guess
<taylan>leoprikler: I mulled it over a bit while driving. I would posit that (equal? #nil '()) doesn't break 'if' because for every other equality predicate EP, "iff (EP a b) then (EP (if a 1 0) (if b 1 0))" continues to hold. so we just "break" equal? so to say.
<leoprikler>I humbly disagree
<leoprikler>using srfi-1 to define your own list equality predicate is not that difficult
<leoprikler>(list= eq? (cons 'a #nil) (cons 'a '()))
<taylan>leoprikler: BTW you can send your objection to https://bugs.gnu.org/48425 so it's documented
<kitzman>i encountered something that it's most probably lack of attention rather than behaviour which I don't know... https://bin.disroot.org/?ad95f95bfe8ef039#D52R2kDN9bZWPTDV5odKDdWNieL1z2EyvjK1fXJBJZwC
<kitzman>the returned exp is matched later, and the lambda is evaluated a couple of times. the error message is that "int-orig" is unbound (line 46). which i find unexpected
<leoprikler>kitzman, I think it would be slightly easier with match-lambda*, but that's a style thing
<leoprikler>I also don't think this definition is safe against expansion attacks
<leoprikler>e.g. ~~TITLE~~ = ~~NAME~~ and ~~NAME~~ = ~~TITLE~~
<leoprikler>or wait, my bad, it does at least only process them once
<leoprikler>but it might make funky replacements, so watch out for those
<leoprikler>I so far don't see the problem with the thing itself, what does peek say?
<kitzman>i'll try match-lambda* i'm a relatively new schemer. also thank you for bringing the expansion attack in my attention, it will be useful later
<kitzman>hmm, the string seems okay.
<kitzman>i think it has smth to do with the quoting - for example if i use a let* and car, name is considered a symbol
<dsmith-work>Shouldn't null? be used for detecting the end-of-list? IIRC, the bit-level values of '() and #nil were very carefully chosen to make null? effient.
<dsmith-work>Instead of comparing directly with '() or #nil ?
<dsmith-work>There were huge debates about this years ago.
<leoprikler>match () does the right thing w.r.t. null checking
<leoprikler>but otherwise yeah, in plain guile use null?