unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* Hash table cursor with delimited continuations
@ 2015-10-01 13:56 Taylan Ulrich Bayırlı/Kammer
  2015-10-02  2:57 ` Mark H Weaver
  2015-10-03 21:21 ` Amirouche Boubekki
  0 siblings, 2 replies; 4+ messages in thread
From: Taylan Ulrich Bayırlı/Kammer @ 2015-10-01 13:56 UTC (permalink / raw)
  To: guile-user

Out of interest, I tried implementing a hash table cursor using
hash-for-each and delimited continuations:

    (use-modules
     (srfi srfi-9)
     (ice-9 hash-table))

    (define-record-type <ht-cursor>
      (make-cursor %cont key value)
      cursor?
      (%cont %cursor-cont)
      (key   cursor-key)
      (value cursor-value))

    (define ht-iter-prompt (make-prompt-tag "ht-iter"))

    (define (ht-cursor ht)
      (call-with-prompt
       ht-iter-prompt
       (lambda ()
         (hash-for-each
          (lambda (k v)
            (abort-to-prompt ht-iter-prompt k v))
          ht))
       (lambda (cont k v)
         (make-cursor cont k v))))

    (define (ht-cursor-next cursor)
      (call-with-prompt
       ht-iter-prompt
       (%cursor-cont cursor)
       (lambda (cont k v)
         (make-cursor cont k v))))

(The cursor would be valid so long as the table isn't mutated.)

But I hit the following problem:

scheme@(guile-user)> (define ht (alist->hash-table '((a . 0) (b . 1))))
scheme@(guile-user)> (define cursor (ht-cursor ht))
scheme@(guile-user)> (cursor-key cursor)
$2 = a
scheme@(guile-user)> (set! cursor (ht-cursor-next cursor))
ERROR: In procedure #<partial-continuation 1a24e00>:
ERROR: Throw to key `vm-error' with args `(vm-run "Unrewindable partial
continuation" (#<vm-continuation 1c7b270>))'.

Entering a new prompt.  Type `,bt' for a backtrace or `,q' to continue.
scheme@(guile-user) [1]>


I couldn't find any direct documentation about this, only some mentions
of "rewindable" flags in the C API in (info "(guile) Dynamic Wind").

Is it a bug, or an undocumented limitation?..  I don't know what I
should generally expect when using delimited continuations with Guile
APIs implemented in C such as hash-for-each.

Thanks in advance,
Taylan



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

* Re: Hash table cursor with delimited continuations
  2015-10-01 13:56 Hash table cursor with delimited continuations Taylan Ulrich Bayırlı/Kammer
@ 2015-10-02  2:57 ` Mark H Weaver
  2015-10-02  6:53   ` Taylan Ulrich Bayırlı/Kammer
  2015-10-03 21:21 ` Amirouche Boubekki
  1 sibling, 1 reply; 4+ messages in thread
From: Mark H Weaver @ 2015-10-02  2:57 UTC (permalink / raw)
  To: Taylan Ulrich "Bayırlı/Kammer"; +Cc: guile-user

taylanbayirli@gmail.com (Taylan Ulrich "Bayırlı/Kammer") writes:

> Out of interest, I tried implementing a hash table cursor using
> hash-for-each and delimited continuations:
>
>     (use-modules
>      (srfi srfi-9)
>      (ice-9 hash-table))
>
>     (define-record-type <ht-cursor>
>       (make-cursor %cont key value)
>       cursor?
>       (%cont %cursor-cont)
>       (key   cursor-key)
>       (value cursor-value))
>
>     (define ht-iter-prompt (make-prompt-tag "ht-iter"))
>
>     (define (ht-cursor ht)
>       (call-with-prompt
>        ht-iter-prompt
>        (lambda ()
>          (hash-for-each
>           (lambda (k v)
>             (abort-to-prompt ht-iter-prompt k v))
>           ht))
>        (lambda (cont k v)
>          (make-cursor cont k v))))
>
>     (define (ht-cursor-next cursor)
>       (call-with-prompt
>        ht-iter-prompt
>        (%cursor-cont cursor)
>        (lambda (cont k v)
>          (make-cursor cont k v))))
>
> (The cursor would be valid so long as the table isn't mutated.)
>
> But I hit the following problem:
>
> scheme@(guile-user)> (define ht (alist->hash-table '((a . 0) (b . 1))))
> scheme@(guile-user)> (define cursor (ht-cursor ht))
> scheme@(guile-user)> (cursor-key cursor)
> $2 = a
> scheme@(guile-user)> (set! cursor (ht-cursor-next cursor))
> ERROR: In procedure #<partial-continuation 1a24e00>:
> ERROR: Throw to key `vm-error' with args `(vm-run "Unrewindable partial
> continuation" (#<vm-continuation 1c7b270>))'.

The problem is that the partial continuation created by
'abort-to-prompt' includes a stack frame for 'hash-for-each', which is
implemented in C.  Guile does not support invoking partial continuations
that include C stack frames.  This is Andy's area, not mine, but I guess
the problem is that we don't have enough information to relocate a C
stack frame.

For now, the solution to problems like this is to avoid implementing
higher-order procedures in C, so that in practice C stack frames are
rarely found in the middle of the stack.

      Mark



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

* Re: Hash table cursor with delimited continuations
  2015-10-02  2:57 ` Mark H Weaver
@ 2015-10-02  6:53   ` Taylan Ulrich Bayırlı/Kammer
  0 siblings, 0 replies; 4+ messages in thread
From: Taylan Ulrich Bayırlı/Kammer @ 2015-10-02  6:53 UTC (permalink / raw)
  To: Mark H Weaver; +Cc: guile-user

Mark H Weaver <mhw@netris.org> writes:

> The problem is that the partial continuation created by
> 'abort-to-prompt' includes a stack frame for 'hash-for-each', which is
> implemented in C.  Guile does not support invoking partial continuations
> that include C stack frames.  This is Andy's area, not mine, but I guess
> the problem is that we don't have enough information to relocate a C
> stack frame.
>
> For now, the solution to problems like this is to avoid implementing
> higher-order procedures in C, so that in practice C stack frames are
> rarely found in the middle of the stack.

I see, thanks for the explanation.

Taylan



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

* Re: Hash table cursor with delimited continuations
  2015-10-01 13:56 Hash table cursor with delimited continuations Taylan Ulrich Bayırlı/Kammer
  2015-10-02  2:57 ` Mark H Weaver
@ 2015-10-03 21:21 ` Amirouche Boubekki
  1 sibling, 0 replies; 4+ messages in thread
From: Amirouche Boubekki @ 2015-10-03 21:21 UTC (permalink / raw)
  To: taylanbayirli; +Cc: guile-user, guile-user-bounces+amirouche=hypermove.net

Le 2015-10-01 15:56, taylanbayirli@gmail.com a écrit :
> Out of interest, I tried implementing a hash table cursor using
> hash-for-each and delimited continuations:
> 

As Mark noted on IRC this is related to 
http://mumble.net/~campbell/scheme/foof-loop.txt

I've hit a similar problem in wiredtiger. wiredtiger is built out 
hashmaps called tables which can be queried using cursors with the 
following procedures:

(cursor-set-key cursor key)
(cursor-search cursor)

Then you can navigate using:

(cursor-next cursor)
(cursor-prev cursor)

One important thing do while scanning a table is to (cursor-reset 
cursor) before re-using the cursor for another scan.

The thing is that my procedure is a composition of stream procedure 
starting with a stream built out of a hashmap cursor. I don't know in 
advance when the cursor must be reset. Let's say (stream-wiredtiger 
"prefix") is a stream over all key/value pairs where key starts with 
"prefix". If I do:

((compose (stream-take 10) stream-wiredtiger) "prefix")

I take only the first 10 elements of the stream and the stream must be 
closed but there is no stream-close procedure.

Instead of using call/cc somehow, I make a list out of 
(stream-wiredtiger "prefix"), reset the cursor and return a stream with 
(list->stream LIST).

Here is the implementation of the list that is used to build 
stream-wiredtiger:

(define (lookup prefix cursor)
   (with-cursor cursor
     (cursor-key-set cursor prefix)
     (if (cursor-search-near cursor)
         (let loop ((atoms (list)))
           ;; make sure it did not go beyond the keys
           ;; we are interested in
           (if (prefix? prefix (cursor-key-ref cursor))
               (let ((atoms (cons (cursor-value-ref cursor) atoms)))
                 ;; is there any other key in the hashmap?
                 (if (cursor-next cursor)
                     (loop atoms)
                     atoms))))
         (list))))

The advantage is that I don't need to use call/cc. The problem is that 
the stream must fit into memory. Also another approach would be to only 
reset the cursor if we fully consume the stream. This will have a small 
performance impact on scanning but will save memory.

This went a little off-topic. I'll just add that outside the fact that 
srfi-41 procedures don't support currying it's basically gremlin 
traversal 
http://tinkerpop.incubator.apache.org/docs/3.0.0-incubating/#traversal


-- 
Amirouche ~ amz3 ~ http://www.hypermove.net



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

end of thread, other threads:[~2015-10-03 21:21 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-10-01 13:56 Hash table cursor with delimited continuations Taylan Ulrich Bayırlı/Kammer
2015-10-02  2:57 ` Mark H Weaver
2015-10-02  6:53   ` Taylan Ulrich Bayırlı/Kammer
2015-10-03 21:21 ` Amirouche Boubekki

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