unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* Continuations: possible newbie question
@ 2002-12-18  0:14 Matt Hellige
  0 siblings, 0 replies; 8+ messages in thread
From: Matt Hellige @ 2002-12-18  0:14 UTC (permalink / raw)


I'm trying to use guile in a software project, and have encountered a
snag. It may be my imperfect understanding of continuations, but it
seems weird. First a little background...

I'm trying to use guile to implement key bindings, planning to bind
key-strokes to thunks. I'd like to be able to write a key binding like:
 (define (mythunk)
  (goto-item (get-string)))
 (bind-key "g" mythunk)

where goto-item and get-string are primitives. Now, the issue is that
get-string needs to do some interaction with the user, so i'd like to
be able to return to the main application loop to do the interaction,
then cause get-string to return the result.

To do this, I figured I could use a combination of exceptions and
call/cc. But I can't seem to get it to work.

I have a simple test case set up that demonstrates the problem.
Given the following definitions:
    (define call/cc call-with-current-continuation)
    (define cont #f)

    (define (get-string)
     (let ((result (call/cc (lambda (c) (set! cont c) #f))))
      (if result
       result
       (throw 'interact))))

    (define (done-reading result)
     (if cont
      (let ((tmp cont))
       (set! cont #f)
       (tmp result))))

    (define (bind)
     (display (get-string))(newline))

    (define (exec-binding thunk)
     (catch 'interact thunk (lambda (key) "escaped")))

Here's what I'd expect:
    guile> (exec-binding bind)
    "escaped"
    guile> (done-reading "hi")
    hi
    guile> 

But here's what I get:
    guile> (exec-binding bind)
    "escaped"
    guile> (done-reading "hi")
    (((()) #<eval-closure 40278f60>))
    guile> 
    guile> 
    guile> (exec-binding bind)
    "escaped"
    guile> (done-reading "hi")
    (#<unknown-immediate 0xaa8dc> #<smob 4001f000> . #i(Segmentation fault

Notice that it changes between the first and second tries, and also
please notice the seg fault... This definitely doesn't seem quite right!
It also behaves similarly if I try (exec-binding get-string), although
it doesn't always crash.

On the other hand, the following seems to work correctly:
    guile> (get-string)
    <unnamed port>: In procedure gsubr-apply in expression (throw (quote
    interact)):
    <unnamed port>: unhandled-exception: interact
    ABORT: (misc-error)

    Type "(backtrace)" to get more information or "(debug)" to enter the
    debugger.
    guile> (done-reading "hi")
    "hi"
    guile> 

The error, of course, is due to the fact that we're no longer in
exec-binding when the exception is thrown.

So, my question basically is: is this due to a bug in guile, or to my
abuse of continuations? Either way, can anyone suggest another way to
do what I'm trying to do? I'm rather new to this, so my solution may
be too convoluted to begin with. If no one here can suggest anything,
is there a more general scheme forum that I could try?

This is all using guile-1.6.0. Thanks very much!

Matt

-- 
Matt Hellige                  matt@immute.net
http://matt.immute.net


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-user


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

* Re: Continuations: possible newbie question
@ 2002-12-18 17:27 Thien-Thi Nguyen
  2002-12-18 18:14 ` Matt Hellige
  0 siblings, 1 reply; 8+ messages in thread
From: Thien-Thi Nguyen @ 2002-12-18 17:27 UTC (permalink / raw)
  Cc: guile-user

   From: Matt Hellige <matt@immute.net>
   Date: Tue, 17 Dec 2002 18:14:25 -0600

   is this due to a bug in guile,

perhaps.  here is what i see:

guile> (version)
"1.4.1.93"
guile> (load "cwcc.scm")		; as posted
guile> (exec-binding bind)
"escaped"
guile> (done-reading "hi")
hi
guile> 

   or to my abuse of continuations?

continuations are basically a sanctioned control-flow abuse mechanism,
so it is all just a matter of degree.  i have been happy not to use them
except as escapes, in my code.  in one gig i used them -- guile 1.3.4, i
believe -- as co-routines (like your example) but that was more to
impress the Boss (and drag myself out of ignorance ;-) than anything.

   another way to do what I'm trying to do?

probably you can continue your explorations in this vein w/ more
debugging support: use `trace' and `pk' to determine where things go
wrong, and/or use a guile version that behaves as you expect.

all other ways essentially devolve into using continuations.

thi


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-user


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

* Re: Continuations: possible newbie question
  2002-12-18 17:27 Continuations: possible newbie question Thien-Thi Nguyen
@ 2002-12-18 18:14 ` Matt Hellige
  2002-12-18 20:04   ` Neil Jerram
  0 siblings, 1 reply; 8+ messages in thread
From: Matt Hellige @ 2002-12-18 18:14 UTC (permalink / raw)


[Thien-Thi Nguyen <ttn@giblet.glug.org>]
> 
>    is this due to a bug in guile,
> 
> perhaps.  here is what i see:
> 
> guile> (version)
> "1.4.1.93"
> guile> (load "cwcc.scm")		; as posted
> guile> (exec-binding bind)
> "escaped"
> guile> (done-reading "hi")
> hi
> guile> 
> 

Well, at this point it definitely seems to be a bug. I tried it in MIT
Scheme as well, although I had to change my example not to use
exceptions. Here's my new code snippet:

    (define call/cc call-with-current-continuation)
    (define cont #f)
    (define escape #f)

    (define (make-escape)
     (if (call/cc (lambda (c) (set! escape (lambda () (c #t))) #f))
      (begin
       (display "escaped")
       (newline))
      (begin
       (display "created escape proc")
       (newline))))

    (define (get-string)
     (let ((result (call/cc (lambda (c) (set! cont c) #f))))
      (if result
       result
       (begin
        (display "escaping... ")
        (escape)))))

    (define (done-reading result)
     (if cont
      (let ((tmp cont))
       (set! cont #f)
       (tmp result))))

    (define (bind)
     (display (get-string))(newline))

Here's what MIT Scheme does:

    1 ]=> (make-escape)
    created escape proc
    ;Unspecified return value

    1 ]=> (bind)
    escaping... escaped
    ;Unspecified return value

    1 ]=> (done-reading "hi")
    hi
    ;Unspecified return value

    1 ]=> (done-reading "there")

    ;Unspecified return value

    1 ]=> 

which is exactly what I'd expect. Here's what Guile 1.6.0 does:

    guile> (make-escape)
    created escape proc
    guile> (bind)
    escaping... escaped
    guile> (done-reading "hi")
    (#<procedure #f (c)>)
    guile> (done-reading "there")
    guile> 
    guile> (get-string)
    escaping... escaped
    guile> (done-reading "hi")
    "hi"
    guile> 

Obviously somewhat less violent than before, but apparently no more
correct... Note that calling get-string directly still seems to work.

Should I create an official bug report for this? What is the right
procedure for doing so?

> 
>    another way to do what I'm trying to do?
> 
> probably you can continue your explorations in this vein w/ more
> debugging support: use `trace' and `pk' to determine where things go
> wrong, and/or use a guile version that behaves as you expect.
> 
> all other ways essentially devolve into using continuations.
> 

Well, at this point I'm depending on 1.6, so that's not really an
option. Plus, I just don't get the feeling that the claims that
guile's non-linear continuations interact correctly with C code are
totally reliable (especially since they seem to have problems even
without C code!), so I'd prefer to avoid using them if possible. Which
really just leaves me with only one choice: re-architect my project so
that the problem goes away. I think that should be OK, now that I know
it's what I need to do.

I imagine someone who's been using Scheme for more than one week would
probably have rather better ideas about this anyway... :)

Thanks for your help, and please let me know what I should do to
submit a bug report!

Take care,
Matt

-- 
Matt Hellige                  matt@immute.net
http://matt.immute.net


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-user


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

* Re: Continuations: possible newbie question
@ 2002-12-18 18:42 Thien-Thi Nguyen
  0 siblings, 0 replies; 8+ messages in thread
From: Thien-Thi Nguyen @ 2002-12-18 18:42 UTC (permalink / raw)
  Cc: guile-user

   From: Matt Hellige <matt@immute.net>
   Date: Wed, 18 Dec 2002 12:14:10 -0600

   what I should do to
   submit a bug report

it's probably sufficient to send a message to bug-guile saying "see
thread ``Continuations: ...'' in guile-user".  the posted snippets are
fine as far as test-cases go.  (-; but this is not "official" policy.)

thi


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-user


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

* Re: Continuations: possible newbie question
  2002-12-18 18:14 ` Matt Hellige
@ 2002-12-18 20:04   ` Neil Jerram
  2002-12-18 23:51     ` Matt Hellige
  0 siblings, 1 reply; 8+ messages in thread
From: Neil Jerram @ 2002-12-18 20:04 UTC (permalink / raw)
  Cc: guile-user

>>>>> "Matt" == Matt Hellige <matt@immute.net> writes:

    Matt> Well, at this point it definitely seems to be a bug.

I tried your original code in my copy of stable branch Guile CVS
(i.e. 1.6.x), and it worked as (you) expected.

So either this has been fixed, in which case you could try the just
released 1.6.1, or it is something trickier to pin down, in which case
what platform are you using etc.?

        Neil



_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-user


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

* Re: Continuations: possible newbie question
  2002-12-18 20:04   ` Neil Jerram
@ 2002-12-18 23:51     ` Matt Hellige
  2002-12-19  0:41       ` Marius Vollmer
  0 siblings, 1 reply; 8+ messages in thread
From: Matt Hellige @ 2002-12-18 23:51 UTC (permalink / raw)


[Neil Jerram <neil@ossau.uklinux.net>]
> >>>>> "Matt" == Matt Hellige <matt@immute.net> writes:
> 
>     Matt> Well, at this point it definitely seems to be a bug.
> 
> I tried your original code in my copy of stable branch Guile CVS
> (i.e. 1.6.x), and it worked as (you) expected.
> 
> So either this has been fixed, in which case you could try the just
> released 1.6.1, or it is something trickier to pin down, in which case
> what platform are you using etc.?
> 

Interesting. At first 1.6.1 showed the same behavior, but I got
suspicious that it was something about my config, and tried rebuilding
with different optimization settings. The problem went away.

I *believe* that the significant change was from -O3 to -O2. Based on
the little that I know about how guile is implemented, this doesn't
surprise me too much: I assume that the optimization somehow broke
guile's stack inspection magic. On the other hand, that could be way
off. As I said, I've been using guile (and scheme) for less than two
weeks now.

In any case, this is almost certainly not a bug in guile, but is it a
known issue with building? Is it documented anywhere that optimization
beyond -O2 may break guile? I couldn't find it in INSTALL, or anywhere
else, but I may have missed it. Perhaps it should be mentioned, as the
resulting behavior is definitely a bit mystifying. :)

On the other hand, I'll probably still not end up using this technique
to implement my call-backs, given the performance penalties and so on.
I hope I can just shuffle things around a bit in my native code...

Thanks very much for your help!

Matt

-- 
Matt Hellige                  matt@immute.net
http://matt.immute.net


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-user


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

* Re: Continuations: possible newbie question
  2002-12-18 23:51     ` Matt Hellige
@ 2002-12-19  0:41       ` Marius Vollmer
  2002-12-19  2:42         ` Matt Hellige
  0 siblings, 1 reply; 8+ messages in thread
From: Marius Vollmer @ 2002-12-19  0:41 UTC (permalink / raw)
  Cc: guile-user

Matt Hellige <matt@immute.net> writes:

> On the other hand, I'll probably still not end up using this technique
> to implement my call-backs, given the performance penalties and so on.
> I hope I can just shuffle things around a bit in my native code...

I would not worry about performance too early.  If you invoke one
continuation for every key press by the user, that should be no
problem.

Here is a little Gtk+ program that shows off continuations.  I still
find it quite instructive...

;; This is an example of how to use continuations with the Gtk event
;; loop.  It implements a dialog box that looks to the programmer like
;; it was modal, and to the user like it was non-modal.  The function
;; `yes-or-no?' that implements this dialog box only returns to the
;; caller when the user has aswered the dialog.  The user however can
;; pop up any number of these dialog boxes and answer them in any
;; order he likes.  The main application stays alive as well.

(use-modules (gtk gtk))

;; The callbacks that have been delayed

(define callbacks '())

;; Our own event-loop.  We remove the callbacks before invoking them
;; so that we don't get confused when the callback reenters the
;; event-loop.

(define (event-loop)
  (cond
   ((not (null? callbacks))
    (let ((c (car callbacks)))
      (set! callbacks (cdr callbacks))
	 (c)
	 (event-loop)))
   ((not (zero? (gtk-main-iteration)))
    (event-loop))))

;; Connect to a signal and arrange for PROC to be consed onto
;; CALLBACKS when the signal is emitted.

(define (gtk-signal-connect-delayed obj sig proc)
  (gtk-signal-connect obj sig 
		      (lambda () (set! callbacks (cons proc callbacks)))))

;; Now for the continuation part.  To implement the non-modal dialog box
;; that can be used from your code like a modal one, we save the
;; continuation of the YES-OR-NO? invokation and reenter the event-loop
;; (after popping up the window).  When a button has been clicked, we
;; destroy the window and invoke the saved continuation with the
;; appropriate return value.

(define (yes-or-no? title)
  (call-with-current-continuation
   (lambda (cont)
     ;; Now CONT is the part of the program that receives our
     ;; return value.

     (let* ((d (gtk-window-new 'dialog))
	    (v (gtk-vbox-new #f 0))
	    (h (gtk-hbox-new #t 0))
	    (l (gtk-label-new title))
	    (s (gtk-hseparator-new))
	    (y (gtk-button-new-with-label "Yes"))
	    (n (gtk-button-new-with-label "No"))

	    (answer (lambda (val)
		      (gtk-widget-destroy d)

		      ;; Here we return to our caller after the
		      ;; dialog has been destroyed.
		      (cont val))))

       (gtk-container-add d v)
       (gtk-box-pack-start v l #f #f 0)
       (gtk-box-pack-start v s #f #f 0)
       (gtk-box-pack-start v h #f #f 0)
       (gtk-box-pack-start h y #f #f 0)
       (gtk-box-pack-start h n #f #f 0)
       (gtk-widget-show-all d)

       ;; Bind ANSWER to the "clicked" signals of the action
       ;; buttons.
       (gtk-signal-connect-delayed y "clicked" (lambda () (answer #t)))
       (gtk-signal-connect-delayed n "clicked" (lambda () (answer #f)))

       ;; Reenter the event-loop.  You can think of this as a goto.
       (event-loop)))))

(define w (gtk-window-new 'toplevel))
(define b (gtk-button-new-with-label "Ok!"))
(gtk-container-add w b)

(gtk-signal-connect-delayed 
 b "clicked" 
 (let ((i 0))
   (lambda () 
     (set! i (1+ i))
     ;; capture I in a local environment so that nobody can alter
     ;; it while YES-OR-NO? does its thing.
     (let ((i i))
       ;; Use YES-OR-NO? as if it were a modal dialog.
       (pk i (yes-or-no? (string-append (number->string i)
					": Really?")))))))

(gtk-signal-connect w "destroy" gtk-exit)

(gtk-widget-show b)
(gtk-widget-show w)

(event-loop)

-- 
GPG: D5D4E405 - 2F9B BCCC 8527 692A 04E3  331E FAF8 226A D5D4 E405


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-user


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

* Re: Continuations: possible newbie question
  2002-12-19  0:41       ` Marius Vollmer
@ 2002-12-19  2:42         ` Matt Hellige
  0 siblings, 0 replies; 8+ messages in thread
From: Matt Hellige @ 2002-12-19  2:42 UTC (permalink / raw)


[Marius Vollmer <mvo@zagadka.ping.de>]
> Matt Hellige <matt@immute.net> writes:
> 
> > On the other hand, I'll probably still not end up using this technique
> > to implement my call-backs, given the performance penalties and so on.
> > I hope I can just shuffle things around a bit in my native code...
> 
> I would not worry about performance too early.  If you invoke one
> continuation for every key press by the user, that should be no
> problem.

Always good advice, of course. In fact I have implemented it that way
for now. In the end, I think performance will be less of a concern for
me than reliability. I admit that I am still somewhat suspicious of
non-linear continuations and C code... :)

So it may change in the future, but for now with my newly rebuilt
libguile, it works like a charm exactly as we've discussed. Thanks all
for your help and advice.

Matt

-- 
Matt Hellige                  matt@immute.net
http://matt.immute.net


_______________________________________________
Guile-user mailing list
Guile-user@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-user


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

end of thread, other threads:[~2002-12-19  2:42 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-12-18 17:27 Continuations: possible newbie question Thien-Thi Nguyen
2002-12-18 18:14 ` Matt Hellige
2002-12-18 20:04   ` Neil Jerram
2002-12-18 23:51     ` Matt Hellige
2002-12-19  0:41       ` Marius Vollmer
2002-12-19  2:42         ` Matt Hellige
  -- strict thread matches above, loose matches on Subject: below --
2002-12-18 18:42 Thien-Thi Nguyen
2002-12-18  0:14 Matt Hellige

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).