Ungexp doesn't work on deep lists

  • Open
  • quality assurance status badge
Details
3 participants
  • Josselin Poiret
  • Ludovic Courtès
  • Justin Veilleux
Owner
unassigned
Submitted by
Justin Veilleux
Severity
normal
J
J
Justin Veilleux wrote on 13 Jan 02:52 +0100
(address . bug-guix@gnu.org)
87v87yvw2y.fsf@cock.li
Hi, I've been using G-expressions for some time and have always been
hindered by `ungexp` not working on deeper lists. For instance, when I
want to embed in a G-expression a list of packages, it works

Toggle quote (7 lines)
>(define packages (list coreutils gnu-make ...))
>
> #~(for-each
> (lambda (f)
> ... do-something)
> '#$packages)

But as soon as I use an object in which the file-like objects are
deeper, it fails

Toggle quote (11 lines)
> (define packages
> (list
> (cons "coreutils" coreutils)
> (cons "make" gnu-make)
> ...))
>
> #~(for-each
> (lambda (f)
> ... do-something)
> '#$packages)

If I send a patch to "fix" this, will it be usefull or is there a reason
for this behavior?

Thanks.
J
J
Josselin Poiret wrote on 13 Jan 12:38 +0100
87ttnhh39d.fsf@jpoiret.xyz
Hi Justin,

Justin Veilleux <terramorpha@cock.li> writes:

Toggle quote (14 lines)
>> (define packages
>> (list
>> (cons "coreutils" coreutils)
>> (cons "make" gnu-make)
>> ...))
>>
>> #~(for-each
>> (lambda (f)
>> ... do-something)
>> '#$packages)
>
> If I send a patch to "fix" this, will it be usefull or is there a reason
> for this behavior?

I think IMO that it's a bug, but it's also quite tricky to properly
traverse deep structures like this. The bug comes from the fact that in
gexp->sexp, we traverse lists by matching the reference with (refs ...),
but that doesn't match if the reference is a pair instead. Then, it
tries to match with ($ <gexp-input> (? self-quoting? x)), which does
match since self-quoting? apparently returns #t on a pair, whether or
not its constituents are also self-quoting.

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

iQHEBAEBCAAuFiEEOSSM2EHGPMM23K8vUF5AuRYXGooFAmWidj4QHGRldkBqcG9p
cmV0Lnh5egAKCRBQXkC5Fhcaij9YDACaNDfeMZsVBnnXyeSYtPhNu3VfkcN1UGZk
sr3n9lFm8dnSJ5buUVNo5vXm34xgwuG+QrNe682Hmd8oj/Hn/oSTCcFn9+jkFpn4
QX7N30P+Rn9fXoB2tpj5B64pv6ITl3jL8Tkw5+l3EZKp4Mrl6QgfOrv8talCj3jv
GDgPNuh+siek7S7u57HZNY5Re9gvhNvNE5XGMmCF47QQcfM76jnmojnxYDSw/aaK
DexShbr/BWwkqSQn0VcinoJ+ASCy/tymqg2Vf/ooaMDDgGWEuz0N1C35qJRkp0GR
DYXn+ffoaHmRqqJpuAfFwInIi4sFFC7OWWlgiRYfRXjniO7JB/wpUKi7xZ9ay3t5
+yK08wlnEAblRPnaS7x0fYhCUIJn5u5goBoGz86oghh05wNM+wuG4pf0WMqRlOww
YF+XG0jrad6JrpC370epzDo/Z5qtJLwp5weDUqs8Q1J0wRyEokbYke+PGiqorLVs
UnPVdmrIYdeTZApTb4olaUXFsJZjgLY=
=PxKF
-----END PGP SIGNATURE-----

L
L
Ludovic Courtès wrote on 15 Jan 10:46 +0100
(name . Josselin Poiret)(address . dev@jpoiret.xyz)
87le8rj5dp.fsf@gnu.org
Hi,

Josselin Poiret <dev@jpoiret.xyz> skribis:

Toggle quote (24 lines)
> Justin Veilleux <terramorpha@cock.li> writes:
>
>>> (define packages
>>> (list
>>> (cons "coreutils" coreutils)
>>> (cons "make" gnu-make)
>>> ...))
>>>
>>> #~(for-each
>>> (lambda (f)
>>> ... do-something)
>>> '#$packages)
>>
>> If I send a patch to "fix" this, will it be usefull or is there a reason
>> for this behavior?
>
> I think IMO that it's a bug, but it's also quite tricky to properly
> traverse deep structures like this. The bug comes from the fact that in
> gexp->sexp, we traverse lists by matching the reference with (refs ...),
> but that doesn't match if the reference is a pair instead. Then, it
> tries to match with ($ <gexp-input> (? self-quoting? x)), which does
> match since self-quoting? apparently returns #t on a pair, whether or
> not its constituents are also self-quoting.

Actually, what bug are we talking about? It seems to work for me with
this example:

Toggle snippet (8 lines)
scheme@(guile-user)> (define packages `(("coreutils" ,coreutils) ("make" ,gnu-make)))
scheme@(guile-user)> ,build (scheme-file "foo" #~(begin '#$packages))
building /gnu/store/lq9gvbilv0y2nph00zxk6bn3lvcgdxqq-foo.drv...
$7 = "/gnu/store/9ryh6v80jvjv3kwx0q782h26h9gbaclj-foo"
scheme@(guile-user)> (call-with-input-file $7 get-string-all)
$8 = "(begin (quote ((\"coreutils\" \"/gnu/store/mppp9hwxizx9g9pikwcvvshb2ffxyq7p-coreutils-9.1\") (\"make\" \"/gnu/store/9fadhs5qmwl5x7f669a0v39b3ryrmmf1-make-4.3\"))))"

One of the design decisions for gexps was to ensure that substituting a
file-like object by its file name would be O(1) in most cases.

Substitution in lists as in the example above is supported, but
primarily for backward compatibility. It should be avoided when
possible because it’s inefficient: ‘gexp->sexp’ needs to traverse the
whole list/tree in search of potential candidates.

Thanks,
Ludo’.
J
J
Josselin Poiret wrote on 15 Jan 17:28 +0100
(name . Ludovic Courtès)(address . ludo@gnu.org)
87bk9m1ry8.fsf@jpoiret.xyz
Hi Ludo,

Ludovic Courtès <ludo@gnu.org> writes:

Toggle quote (20 lines)
> Actually, what bug are we talking about? It seems to work for me with
> this example:
>
> --8<---------------cut here---------------start------------->8---
> scheme@(guile-user)> (define packages `(("coreutils" ,coreutils) ("make" ,gnu-make)))
> scheme@(guile-user)> ,build (scheme-file "foo" #~(begin '#$packages))
> building /gnu/store/lq9gvbilv0y2nph00zxk6bn3lvcgdxqq-foo.drv...
> $7 = "/gnu/store/9ryh6v80jvjv3kwx0q782h26h9gbaclj-foo"
> scheme@(guile-user)> (call-with-input-file $7 get-string-all)
> $8 = "(begin (quote ((\"coreutils\" \"/gnu/store/mppp9hwxizx9g9pikwcvvshb2ffxyq7p-coreutils-9.1\") (\"make\" \"/gnu/store/9fadhs5qmwl5x7f669a0v39b3ryrmmf1-make-4.3\"))))"
> --8<---------------cut here---------------end--------------->8---
>
> One of the design decisions for gexps was to ensure that substituting a
> file-like object by its file name would be O(1) in most cases.
>
> Substitution in lists as in the example above is supported, but
> primarily for backward compatibility. It should be avoided when
> possible because it’s inefficient: ‘gexp->sexp’ needs to traverse the
> whole list/tree in search of potential candidates.

Notice that OP's example uses `(("thing" . ,package)), ie. lists of
pairs and not lists of lists, as in your case!

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

iQHEBAEBCAAuFiEEOSSM2EHGPMM23K8vUF5AuRYXGooFAmWlXT8QHGRldkBqcG9p
cmV0Lnh5egAKCRBQXkC5FhcairojC/9CurDR/TEqvZIn0O5WeT385pUtJ2PgC0GY
qsCzJQxvQN3LwMRmK+Lp3J5jvHKkMCqh6ufyc5FhrsSaiWS6Il0dfzLhwfqwnAFz
18iw46Q/8CQ8myxxa0rCxuwQEBmy6vMfl1We56wGC8UPChM9QRXWbthv/1TLctCD
yhKYv4nDjkpkT/nf/EhTOrdCeTuzve7CUkeud21uQ7q+bYLRkXnUfoHDQ+qIan3m
SuYnnUDLPfzVJSZuxTxQ+DeI4TNFibrkwWzpGgsjFE4PcqDkgcRCe9oPF20XcmJA
S9IzPcRF34bzp3IHipU5JmlRXYwGJriAAI5sImpm0jq2DaKHGshd9hwYUzw1obR5
0CLPpM/yksZOX2H2z3L5UZTnSZENs49k/LfR6LQpU2sDAsk0OE+ODoGgzQ0AYxJ8
EZxCn3TatNpZIxEmrLubqpCT0c5gXZU/NmJnQ2PPhDcDbtt2iupMhFMBjTifnTXG
wFrQJHKdWWLhwLBjdStzgXcPznlk888=
=lsmz
-----END PGP SIGNATURE-----

?