unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* or values bug?
@ 2011-12-05 14:33 rixed
  2011-12-05 17:40 ` Ludovic Courtès
  2011-12-06  6:51 ` rixed
  0 siblings, 2 replies; 7+ messages in thread
From: rixed @ 2011-12-05 14:33 UTC (permalink / raw)
  To: guile-user

Is it normal that this:

(or (values 'a 'b) 'c)

returns two values ('a and 'b) while this:

(or (values 'a (lambda (port) #f)) 'c)

returns only one ('a)?
Isn't it a bug?




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: or values bug?
  2011-12-05 14:33 or values bug? rixed
@ 2011-12-05 17:40 ` Ludovic Courtès
  2011-12-05 20:57   ` Andy Wingo
  2011-12-06  6:51 ` rixed
  1 sibling, 1 reply; 7+ messages in thread
From: Ludovic Courtès @ 2011-12-05 17:40 UTC (permalink / raw)
  To: guile-user

Hi Cédric,

rixed@happyleptic.org skribis:

> Is it normal that this:
>
> (or (values 'a 'b) 'c)
>
> returns two values ('a and 'b)

This one gets optimized by peval:

  scheme@(guile-user)> ,optimize (or (values 1 2) 'b)
  $6 = (values 1 2)

That the second value isn’t truncated is a bug (see below.)

> while this:
>
> (or (values 'a (lambda (port) #f)) 'c)
>
> returns only one ('a)?

This one doesn’t:

  scheme@(guile-user)> ,optimize (or (values 1 (lambda () #t)) 'b)
  $5 = (begin
    (letrec*
      ()
      (let ((#{t 1263}# (values 1 (lambda () #t))))
        (if #{t 1263}# #{t 1263}# 'b))))

The ‘let’, which leads to the second value being ignored, comes from the
definition of ‘or’:

  (define-syntax or
    (syntax-rules ()
      ((_) #f)
      ((_ x) x)
      ((_ x y ...) (let ((t x)) (if t t (or y ...))))))

It’s normal that the second value is ignored because ‘or’ expects
expressions returning one value.

In theory, peval should really optimize the first form to 1, instead of
multiple-values, but I think it loses information about the context
somewhere.

Namely, when partial-evaluating <let> forms, I think it should:

   (let* ((vars (map (compose truncate lookup-var) gensyms))
          ...)
     ...)

where ‘truncate’ discards all values but the first of a <let-values>
form.

Andy?

Thanks,
Ludo’.




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: or values bug?
  2011-12-05 17:40 ` Ludovic Courtès
@ 2011-12-05 20:57   ` Andy Wingo
  2011-12-05 21:00     ` Andy Wingo
  0 siblings, 1 reply; 7+ messages in thread
From: Andy Wingo @ 2011-12-05 20:57 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guile-user

On Mon 05 Dec 2011 18:40, ludo@gnu.org (Ludovic Courtès) writes:

>   scheme@(guile-user)> ,optimize (or (values 1 2) 'b)
>   $6 = (values 1 2)
>
> That the second value isn’t truncated is a bug (see below.)

Indeed.

>    (let* ((vars (map (compose truncate lookup-var) gensyms))
>           ...)
>      ...)

Better to truncate when adding variables to all expand-time
environments, I would think, in the form of `(cut make-primcall #f
'values <>)'.

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: or values bug?
  2011-12-05 20:57   ` Andy Wingo
@ 2011-12-05 21:00     ` Andy Wingo
  2011-12-06 17:57       ` Ludovic Courtès
  0 siblings, 1 reply; 7+ messages in thread
From: Andy Wingo @ 2011-12-05 21:00 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guile-user

On Mon 05 Dec 2011 21:57, Andy Wingo <wingo@pobox.com> writes:

>>    (let* ((vars (map (compose truncate lookup-var) gensyms))
>>           ...)
>>      ...)
>
> Better to truncate when adding variables to all expand-time
> environments, I would think, in the form of `(cut make-primcall #f
> 'values <>)'.

Rather, something like:

   (define (truncate x)
     (match x
       ((<const>) x)
       ;; similar provably singly-valued cases here
       (else (make-primcall #f 'values (list x)))))

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: or values bug?
  2011-12-05 14:33 or values bug? rixed
  2011-12-05 17:40 ` Ludovic Courtès
@ 2011-12-06  6:51 ` rixed
  1 sibling, 0 replies; 7+ messages in thread
From: rixed @ 2011-12-06  6:51 UTC (permalink / raw)
  To: guile-user


Thank you to both of you for the explanations and for looking 
for a solution so quickly.
Anyway, I changed my code to not use this evil multiple value feature and I
think I will keep away from this. Returning a list seams so much natural.

Do you need me actualy fill a bugreport?




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: or values bug?
  2011-12-05 21:00     ` Andy Wingo
@ 2011-12-06 17:57       ` Ludovic Courtès
  2011-12-06 18:23         ` Andy Wingo
  0 siblings, 1 reply; 7+ messages in thread
From: Ludovic Courtès @ 2011-12-06 17:57 UTC (permalink / raw)
  To: guile-user

[-- Attachment #1: Type: text/plain, Size: 637 bytes --]

Hi Andy,

Andy Wingo <wingo@pobox.com> skribis:

> Rather, something like:
>
>    (define (truncate x)
>      (match x
>        ((<const>) x)
>        ;; similar provably singly-valued cases here
>        (else (make-primcall #f 'values (list x)))))

I’ve started poking at it and the main difficulty is that we now need to
know, for any procedure, whether it’s provably singly-valued.

I suspect it’s often the case that it cannot be proved, for instance
when a lambda calls a top-level.  In all those cases, we’d end up
wrapping the expression in (values (list EXP)), which seems like a bad
idea.

Thoughts?

Thanks,
Ludo’.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: text/x-patch, Size: 3489 bytes --]

diff --git a/module/language/tree-il/peval.scm b/module/language/tree-il/peval.scm
index 634c6c9..b4f5144 100644
--- a/module/language/tree-il/peval.scm
+++ b/module/language/tree-il/peval.scm
@@ -99,6 +99,42 @@
            (or (proc (vlist-ref vlist i))
                (lp (1+ i)))))))
 
+(define (truncate-values x)
+  "Discard all but the first value of X."
+  (let loop ((x x))
+    (match x
+      (($ <const>) x)
+      (($ <lexical-ref>) x)
+      (($ <void>) x)
+      (($ <lexical-ref>) x)
+      (($ <primitive-ref>) x)
+      (($ <module-ref>) x)
+      (($ <toplevel-ref>) x)
+      (($ <conditional> src condition subsequent alternate)
+       (make-conditional src condition (loop subsequent) (loop alternate)))
+      (($ <application> src ($ <primitive-ref> _ 'values) (first _ ...))
+       first)
+      (($ <application> _ ($ <primitive-ref>))
+       ;; Assume all other primitives return at most one value.
+       x)
+      (($ <sequence> src (exps ... last))
+       (make-sequence src (append exps (list (loop last)))))
+      (($ <lambda>) x)
+      (($ <dynlet> src fluids vals body)
+       (make-dynlet src fluids vals (loop body)))
+      (($ <let> src names gensyms vals body)
+       (make-let src names gensyms vals (loop body)))
+      (($ <letrec> src in-order? names gensyms vals body)
+       (make-letrec src in-order? names gensyms vals (loop body)))
+      (($ <fix> src names gensyms vals body)
+       (make-fix src names gensyms vals body))
+      (($ <let-values> src exp body)
+       (make-let-values src exp (loop body)))
+      (else
+       (make-application (tree-il-src x)
+                         (make-primitive-ref #f'values)
+                         (list x))))))
+
 ;; Peval will do a one-pass analysis on the source program to determine
 ;; the set of assigned lexicals, and to identify unreferenced and
 ;; singly-referenced lexicals.
@@ -278,8 +314,10 @@
   (constant-value operand-constant-value set-operand-constant-value!))
 
 (define* (make-operand var sym #:optional source visit)
+  ;; Bind SYM to VAR, with value SOURCE.
   ;; Bound operands are considered copyable until we prove otherwise.
-  (%make-operand var sym visit source 0 #f (and source #t) #f #f))
+  (let ((source (if source (truncate-values source) source)))
+    (%make-operand var sym visit source 0 #f (and source #t) #f #f)))
 
 (define (make-bound-operands vars syms sources visit)
   (map (lambda (x y z) (make-operand x y z visit)) vars syms sources))
diff --git a/test-suite/tests/tree-il.test b/test-suite/tests/tree-il.test
index 5e02bd1..57fd1f4 100644
--- a/test-suite/tests/tree-il.test
+++ b/test-suite/tests/tree-il.test
@@ -664,6 +664,28 @@
           (+ a b))))
     (const 3))
 
+  (pass-if-peval resolve-primitives
+    ;; First order, multiple values.
+    (let ((x 1) (y 2))
+      (values x y))
+    (apply (primitive values) (const 1) (const 2)))
+
+  (pass-if-peval resolve-primitives
+    ;; First order, multiple values truncated.
+    (let ((x (values 1 'a)) (y 2))
+      (values x y))
+    (apply (primitive values) (const 1) (const 2)))
+
+  (pass-if-peval resolve-primitives
+    ;; First order, multiple values truncated.
+    (or (values 1 2) 3)
+    (const 1))
+
+  (pass-if-peval resolve-primitives
+    ;; First order, multiple values truncated in arguments.
+    (+ (values 1 2 3) 2)
+    (const 3))
+
   (pass-if-peval
     ;; First order, coalesced, mutability preserved.
     (cons 0 (cons 1 (cons 2 (list 3 4 5))))


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: or values bug?
  2011-12-06 17:57       ` Ludovic Courtès
@ 2011-12-06 18:23         ` Andy Wingo
  0 siblings, 0 replies; 7+ messages in thread
From: Andy Wingo @ 2011-12-06 18:23 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guile-user

Hey, thanks for looking at this!

On Tue 06 Dec 2011 18:57, ludo@gnu.org (Ludovic Courtès) writes:

> Hi Andy,
>
> Andy Wingo <wingo@pobox.com> skribis:
>
>> Rather, something like:
>>
>>    (define (truncate x)
>>      (match x
>>        ((<const>) x)
>>        ;; similar provably singly-valued cases here
>>        (else (make-primcall #f 'values (list x)))))
>
> I suspect it’s often the case that it cannot be proved, for instance
> when a lambda calls a top-level.  In all those cases, we’d end up
> wrapping the expression in (values (list EXP)), which seems like a bad
> idea.

For the purposes of peval, this is probably fine.  Are there any
expressions for which we don't know the number of values that we allow
to propagate?

But if the operand residualizes, it would be nice to avoid turning

  (let ((x (foo))) (+ 1 x))

into

  (let ((x (values (foo)))) (+ 1 x))

as in this case the `values' is completely unnecessary.  Peval could
handle it, or compile-glil.scm could handle it.

Other than those comments, the patch looks nice to me!

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2011-12-06 18:23 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-12-05 14:33 or values bug? rixed
2011-12-05 17:40 ` Ludovic Courtès
2011-12-05 20:57   ` Andy Wingo
2011-12-05 21:00     ` Andy Wingo
2011-12-06 17:57       ` Ludovic Courtès
2011-12-06 18:23         ` Andy Wingo
2011-12-06  6:51 ` rixed

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).