Ungexp inside vector problem

  • Open
  • quality assurance status badge
Details
2 participants
  • Andrew Tropin
  • Josselin Poiret
Owner
unassigned
Submitted by
Andrew Tropin
Severity
normal
A
A
Andrew Tropin wrote on 20 Mar 2023 06:49
(address . bug-guix@gnu.org)
87v8iw3rbg.fsf@trop.in
I would expect two last expressions return the same result, but the
former one doesn't do ungexp:

Toggle snippet (14 lines)
(define a '(3 4))

(define b `#(1 2 ,a))

(eval-with-store
#~(list '(1 2 #$a))) ;; => ((1 2 (3 4)))

(eval-with-store
#~(list #(1 2 #$a))) ;; => (#(1 2 (ungexp a)))

(eval-with-store
#~(list #$b)) ;; => (#(1 2 4))

Am I doing/expecting something wrong or there is a bug here?

--
Best regards,
Andrew Tropin
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmQX8/QACgkQIgjSCVjB
3rDkuQ/8D8JqMJ6GRv/+pFUDIvaR1KpVV1UkJmDtoDYNJsPQN1isirrZbtSPYXYt
bWEaRsYJapBTB4whqm+Eu3ygqOSBbJq5mfgLV9u2K54Lij0nHVRqW1a/8Cz163zW
RStimNJ/6R2XchrBB9FouXIXbPuIDzGTGYC97F1JkEOYHX0fEd++9N/L0QgieF8w
bc4nA1UyoosEnnqoFTpu3RIQF53oQ1xSmUBXpu9hYqr3bsjM/MdqbUGD36BRgIoH
iVgki+pV7brIyLJ5pO7bJKW8mS1Hm+vAtJTz25g/h8R9qtOha37YsQETScS6Nc0x
zImc0RkiZHSY+Qj8yC5WuJIfajKPBY1/0ElzNGB75kqDmyQt12ixX7xZGe0GMzZU
Syvov8wuEwflRsWv8KyjX1P1iLO8Hi1BSYYbo7MBUKhT2E5JTcY0Gl1VNw2LS79w
f3WT9CrcijVus0qkmYVdi0iBOBAKBruDP9ui3PdyRyVg1tACJowB5nitT2UrhPYU
E68/XYiaCnAlFENbC4CtCHC4jv4XvSrCBHo5tV5qLbKae9oq0e0GYgZOEGGlZtZ6
2sVtTdZvJj2Hc4mwLQ72x1LOtPl5JWD81bm4mDq+KCSIBeksF8cltwB/mxvs/ScU
WcA5+px2IcNM3nvZblDQYgXkng4/vT9SiXlIzlcPJzc48L/5p34=
=RioR
-----END PGP SIGNATURE-----

J
J
Josselin Poiret wrote on 20 Mar 2023 11:45
875yavsnuw.fsf@jpoiret.xyz
Hi Andrew,

Andrew Tropin <andrew@trop.in> writes:

Toggle quote (20 lines)
> I would expect two last expressions return the same result, but the
> former one doesn't do ungexp:
>
> --8<---------------cut here---------------start------------->8---
> (define a '(3 4))
>
> (define b `#(1 2 ,a))
>
> (eval-with-store
> #~(list '(1 2 #$a))) ;; => ((1 2 (3 4)))
>
> (eval-with-store
> #~(list #(1 2 #$a))) ;; => (#(1 2 (ungexp a)))
>
> (eval-with-store
> #~(list #$b)) ;; => (#(1 2 4))
> --8<---------------cut here---------------end--------------->8---
>
> Am I doing/expecting something wrong or there is a bug here?

It's more related to how the guile reader works, and this is such a
corner case that I don't know whether we should fix. Basically,
anything starting with # is a reader extension, and the next character
identifies which extension it is. #( is the reader extension for
vectors, #~ for gexp and #$ for ungexp.

To simplify, whenever you use #~, guile will insert (gexp ...) instead,
which is a hygienic macro (not just a procedure!), that will look for
ungexps inside the expression. That traversal is only made on cons
cells though, so it doesn't try to go through any piece of syntax that
is not a cons cell! Since #( doesn't expand to a (vector ...)
cons-cell, the subexpression gets ignored for traversal.

This is in contrast to another reader extension, #' (for syntax), which
does expand to (syntax ...), and is thus further traversed!

You can find how both of these reader extensions operate in
<libguile/read.c>.

I guess the immediate fix is to use (vector ...) rather than #(...). We
could also add code to the gexp traversal to also traverse vectors, but
I am not even sure if they go through the gexp->sexp dance unharmed, and
we also should in principle do that for everything that can get into a
gexp, not just vectors (eg. bytevectors).

Best,
--
Josselin Poiret
-----BEGIN PGP SIGNATURE-----

iQHEBAEBCAAuFiEEOSSM2EHGPMM23K8vUF5AuRYXGooFAmQYOTcQHGRldkBqcG9p
cmV0Lnh5egAKCRBQXkC5FhcaimIGC/9UazBvJmF/Mwufblx4XfuVV2UhkFAmvj8Q
DI6j39wa6lU4ILgxuN64Bw9qmreityeJH+gRS3mjP5Cjpg5wVEKCqxfiEMVzt/aZ
TJCG/BEAwpQCvNh0n/mDt5I6nwCYlLfUkoilI4oIvk+2CksDLAX0Z5c0XHNLCrPo
mQQaq00qllMmpWAl2xOblSOa3guYh549QzJxuA0bx+usY0RE9LPUgIL2yZFLMo/A
kCkqPfv0SJPH+Oq5Yn0SNgBpMUUJtoaIMP3Wv6PhzDuZ5IC/8YdC7KR4Pk48a6r3
yvesdch64ywCgTKbJ44LjHj8SLr7ya2R6haUYrf1evIquOOVB+itmEeoyYhiYmCu
DRAeBW1vpSfjrdkBRBgFUc5vFa9O9C/mOPJ+53sbRJQF2G2mZVAFmc+Yp/U4MUnQ
KkMgJrPwTWjnWHoIH3w9BOukNgK+t9WVqpkPaaFlHTBmeOBbncbgOqFmuDJiu/ko
Tk8uWDXTaeO6wZ6RxbQUf9ZAo6zX0Q0=
=oVql
-----END PGP SIGNATURE-----

A
A
Andrew Tropin wrote on 15 Jun 2023 04:57
87edmdh1pz.fsf@trop.in
On 2023-03-20 11:45, Josselin Poiret wrote:

Toggle quote (50 lines)
> Hi Andrew,
>
> Andrew Tropin <andrew@trop.in> writes:
>
>> I would expect two last expressions return the same result, but the
>> former one doesn't do ungexp:
>>
>> --8<---------------cut here---------------start------------->8---
>> (define a '(3 4))
>>
>> (define b `#(1 2 ,a))
>>
>> (eval-with-store
>> #~(list '(1 2 #$a))) ;; => ((1 2 (3 4)))
>>
>> (eval-with-store
>> #~(list #(1 2 #$a))) ;; => (#(1 2 (ungexp a)))
>>
>> (eval-with-store
>> #~(list #$b)) ;; => (#(1 2 4))
>> --8<---------------cut here---------------end--------------->8---
>>
>> Am I doing/expecting something wrong or there is a bug here?
>
> It's more related to how the guile reader works, and this is such a
> corner case that I don't know whether we should fix. Basically,
> anything starting with # is a reader extension, and the next character
> identifies which extension it is. #( is the reader extension for
> vectors, #~ for gexp and #$ for ungexp.
>
> To simplify, whenever you use #~, guile will insert (gexp ...) instead,
> which is a hygienic macro (not just a procedure!), that will look for
> ungexps inside the expression. That traversal is only made on cons
> cells though, so it doesn't try to go through any piece of syntax that
> is not a cons cell! Since #( doesn't expand to a (vector ...)
> cons-cell, the subexpression gets ignored for traversal.
>
> This is in contrast to another reader extension, #' (for syntax), which
> does expand to (syntax ...), and is thus further traversed!
>
> You can find how both of these reader extensions operate in
> <libguile/read.c>.
>
> I guess the immediate fix is to use (vector ...) rather than #(...). We
> could also add code to the gexp traversal to also traverse vectors, but
> I am not even sure if they go through the gexp->sexp dance unharmed, and
> we also should in principle do that for everything that can get into a
> gexp, not just vectors (eg. bytevectors).
>

Thank you very much for extensive explanation! I have a few tasks
related to the guile reader extensions, so when I get my hands dirty
with it, I'll probably share my new thoughts and opinions on this topic.

--
Best regards,
Andrew Tropin
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEKEGaxlA4dEDH6S/6IgjSCVjB3rAFAmSKfggACgkQIgjSCVjB
3rC66A//WKBxTBLKv9zB80gtSCAG/D5IB8fidUHVPc22ih+t7Yi4MreNBOp4Oce9
O/0pbc/rolBfpm1CrYnX/Ug/j10miq7gpwZYKR6neO2iS6zpMee/hta2RBgCHGSS
toBBLk+D+mUdWNk70vy1ZKXxPPBVw8pYA1yZ0YusPvTuy83CPAq8HbFgj6RK3iAB
QGxjui+XCUP9vYUZGsCk1YlVbN9E1qGWxfbxvEXudB1XuZ1widj+SxRN0i1Arq5n
cmPUq0+rI/Bq7247myIKDolCcAOEumqJttsM+Mw9pD28e1CI6EiYxxD/adxrM8NQ
/7eEeiLzsR3Sj4SC9uOlDoEreiAbUCU+Wy4bencDBn8Vv07MkeOzriu/+qgxCSr0
P9WnjdU/qGmHQ0aZLTcRFEhbwQgKh2Em/hmheC1qtffGn46GMVHGKdzRyLEsM3Kg
y0SWMgh1qwv/ELQUVACLcoLtdGX0ibzBBfY8IMHboF6Kes8AeQW45DcBtW2N76TB
xkH/qMVBgJDzBgZauQT9vs7/mQEwrD+Qawkx9hrSBa0/1nZjVTkBo9w2nTro5Zx/
4LP60t7klfpbzSXS1sQc9TWUj5qCzMDIg2953t6UrtCeup4sjltPyGvqriFKF1mX
L3VM5cOvAoTkQal4JSYzLdfDEU8FmKE0mBXsKrdIagzqA9UbHt8=
=yxjj
-----END PGP SIGNATURE-----

?