Re: Announcing 8sync: an asynchronous programming language for Guile

2015-12-09 Thread Christopher Allan Webber
William ML Leslie writes:

> On 6 December 2015 at 01:58, Christopher Allan Webber
>  wrote:
>> Amirouche Boubekki writes:
>>> 8sync has two types of async-request:
>>>
>>> ** run-requests, which implements kind of a *coroutine* behavior.
>>>
>>> It pause the execution of the current procedure and schedule
>>> the provided lambda to be run soonish; This doesn't exists in
>>> async.scm. The only thing useful this can do, is break the callstack
>>> to allow deeper recursion.
>
> An aside on concurrency models: being able to do this - pause
> execution of one turn and allow another to run - creates a strictly
> more powerful model, but with very different properties for the
> purposes of analysis and auditing.  It means that any time you call a
> function, you need to ensure that if there are properties that a turn
> must maintain - such as there being a constant amount of money in the
> system, for example - that this property is maintained /before/ the
> call.
>
> This feature is known as 'stale stack frames' in the literature
> (particularly in E circles), and in an ideal async world, we'd never
> need to do this.  There's a really accessible post at
> https://glyph.twistedmatrix.com/2014/02/unyielding.html about what can
> happen as codebases grow in a system with the potential for stale
> stack frames.  I also think
> https://wingolog.org/archives/2012/02/16/unexpected-concurrency is
> good to review when discussing this, even though it's dealing with a
> slightly different cause.
>
> I'm not saying that it's a bad idea to expose it in 8sync, btw.  One
> great thing about Guile is that it gives you options about how you
> want to do concurrency.  But libraries that use this feature (or may
> decide to use it in the future) should come with a large, flashing
> warning - calling these functions may allow other events to run!

You're right that these are challenging problems... there are a number
of ways to mitigate them, like using the actor model, etc (which of
course still doesn't give you a perfect model of concurrency) or build a
purely funcitonal system on top where you *expect* that a function is
only computing based off of the information that came into the system,
or many other approaches.

But I think it is possible, and best, to leave answering this question
out of the low-level part of 8sync's scheduler.  Instead, systems can be
built on top of it, both bundled with 8sync, and outside of it as
separate packages.  I think that's the best approach... I already intend
to build an actor model system on top of 8sync and attempt to experiment
with some other systems too.  I'd like 8sync's core to be generic enough
where multiple approaches can be built *on top* of it.

I think the current path 8sync is going down makes that possible.

Anyway, good things to keep in mind! :)



Re: Announcing 8sync: an asynchronous programming language for Guile

2015-12-06 Thread Amirouche Boubekki

Le 2015-12-05 15:58, Christopher Allan Webber a écrit :

Amirouche Boubekki writes:


* Agenda

** The canonical callback based event loop API is not visible enough

It should be obvious coming from outside Guile world what/where
is the event loop. As such, agenda doesn't seem like a good name.


"Agenda" is not a unique name for this.  That's what SICP uses, that's
what Sly uses.



Ok with agenda, maybe that's a native idiom I don't get.

Still I think that the canonical event loop API should be implemented
in an obvious way. If otherwise, it should be clear why it's not done 
that

way. In my implementation I don't rely on intermediate data-structures
and it's obvious imho:

- how to run procedure in the loop asap
- how to register a callback to run when a port is ready
- how to pause a procedure until a port is ready

And afaik, it doesn't forbid functional programming. The only mutations
that happen, happen inside the loop primitives to register and run 
select

callbacks.




** Agenda has both `schedule` and `queue`

For a proof of concept, queue/schedule is not useful to demonstrate
the purpose of eightsync as it's an optimization.


It's no mere optimization.  "schedule" is future events that haven't
been queued; it's only for time-delayed events.  The queue is for 
things

that must be done immediately.


Sure it is an optimisation. Only `schedule` is needed to implemented
both "call later" and "call asap" which is "call later" with a delay of 
0.




Re: Announcing 8sync: an asynchronous programming language for Guile

2015-12-06 Thread William ML Leslie
On 6 December 2015 at 01:58, Christopher Allan Webber
 wrote:
> Amirouche Boubekki writes:
>> 8sync has two types of async-request:
>>
>> ** run-requests, which implements kind of a *coroutine* behavior.
>>
>> It pause the execution of the current procedure and schedule
>> the provided lambda to be run soonish; This doesn't exists in
>> async.scm. The only thing useful this can do, is break the callstack
>> to allow deeper recursion.

An aside on concurrency models: being able to do this - pause
execution of one turn and allow another to run - creates a strictly
more powerful model, but with very different properties for the
purposes of analysis and auditing.  It means that any time you call a
function, you need to ensure that if there are properties that a turn
must maintain - such as there being a constant amount of money in the
system, for example - that this property is maintained /before/ the
call.

This feature is known as 'stale stack frames' in the literature
(particularly in E circles), and in an ideal async world, we'd never
need to do this.  There's a really accessible post at
https://glyph.twistedmatrix.com/2014/02/unyielding.html about what can
happen as codebases grow in a system with the potential for stale
stack frames.  I also think
https://wingolog.org/archives/2012/02/16/unexpected-concurrency is
good to review when discussing this, even though it's dealing with a
slightly different cause.

I'm not saying that it's a bad idea to expose it in 8sync, btw.  One
great thing about Guile is that it gives you options about how you
want to do concurrency.  But libraries that use this feature (or may
decide to use it in the future) should come with a large, flashing
warning - calling these functions may allow other events to run!

-- 
William Leslie

Notice:
Likely much of this email is, by the nature of copyright, covered
under copyright law.  You absolutely MAY reproduce any part of it in
accordance with the copyright law of the nation you are reading this
in.  Any attempt to DENY YOU THOSE RIGHTS would be illegal without
prior contractual agreement.



Re: Announcing 8sync: an asynchronous programming language for Guile

2015-12-05 Thread Christopher Allan Webber
Amirouche Boubekki writes:

>> Le 2015-12-04 03:47, Amirouche Boubekki a écrit :
>> 
>>>Le 2015-12-04 03:15, Amirouche Boubekki a écrit :
>>> 
>>>```
>>>(define (read/ sock)
>>>  (abort-to-prompt 'loop (lambda (cc)
>>>   (loop-add-reader sock (lambda () (cc 
>>> (read
>>>sock)))
>>>```
>>> 
>> 
>>This is a mistake, it *must* be a macro
>> 
>
> This will only help with debugging but not catching error and
> dealing with them at runtime ie. it doesn't propagate the exception
> but it can be done and requires a form similar to 
> propagate-%async-exceptions.
>
> TBH the code still seems complex maybe complicated. FWIW here is
> what I think right now. Be warned that everything should be taken
> with a grain of salt.
>
> * Agenda
>
> ** The canonical callback based event loop API is not visible enough
>
> It should be obvious coming from outside Guile world what/where
> is the event loop. As such, agenda doesn't seem like a good name.

"Agenda" is not a unique name for this.  That's what SICP uses, that's
what Sly uses.

> ** Agenda has both `schedule` and `queue`
>
> For a proof of concept, queue/schedule is not useful to demonstrate
> the purpose of eightsync as it's an optimization.

It's no mere optimization.  "schedule" is future events that haven't
been queued; it's only for time-delayed events.  The queue is for things
that must be done immediately.

This separation is very intentional.

> ** `(current-agenda-prompt)`
>
> No need to throw, there should always be a current agenda.

That's not true, if no agenda has been started, %current-agenda will be
#f, so there will be no way to retrieve the current agenda's prompt tag.

> * 
>
> Schedule should be in its own file. Also, in place of:
>
> ```
> (define-record-type 
>(make-schedule-intern segments)
>schedule?
>(segments schedule-segments set-schedule-segments!))
> ```
>
> I prefer:
>
> ```
> (define-record-type 
>(%make-schedule segments)
>schedule?
>(segments schedule-segments-ref schedule-segments-set!))
> ```

%make-schedule might be better.

> Use of `*-ref` and `*-set!`.

-ref is extra typing.  Doing just schedule-segments fits within
conventions shown elsewhere in the manual.

I don't really want to encourage mutation; getters are the default.

> Or better: `(define-record-type*  segments)` (actually I
> think this macro should be in Guile, since it much easier to
> introduce  to new devs).
>
> ** `time` procedures have equivalent in Guile

Yeah I might change that.

> *** `tdelta` is not useful.

tdelta is used so the the agenda knows to put it a future time from the
current execution of the agenda.

> * ``
>
> ** `run-it`
>
> It's sound like it's a `(loop-call-soon callback #:optional (delay 0))`
> procedure.
>
> Instead it's a `(make-run-request proc #:optional time)`.
>
> It's never used.
>
> I'd rather to use a `delay`, and let the devs compute the correct delay,
> when they wants to run something at an absolute time to limit the
> proliferation of sugar procedure in the library.

You're right, it's never really used at present.  There is a difference
between (run (foo)) and (run-it foo) which isn't just the optional #:when,
which can indeed be handled by using run-at or run-delay instead.

Here's the difference: run uses (wrap) to do a friendly
wrap-in-a-thunk.  So you can do to this:


  (define (my-handler)
(let ((foo (bar)))
   (run (mork foo

and behind the scenes, it constructs (lambda () (mork foo)) there,
preserving lexically scoped varibles.

If you already have a thunk though, you can just pass it in.  In such a
case you'd normally need to give another layer of indirection with
(run (my-thunk)).

It's an optimization that might not be necessary.  I might remove
it... I'm going to wait and see.

> *** `(wrap e ...)` and `(wrap-apply body)`
>
> I'm pretty sure that `wrap` can be written using `wrap-apply`. This
> looks suspicious for several reasons.

There's a difference between them:

 - (run) uses (wrap) to wrap all body contents in a thunk, preserving
   the illusion that everything looks the same as running code inline,
   as described above.  For most code, that's what you want.  (wrap)
   basically makes making inline thunks a little cleaner, and hands that
   off to other macros which make thunks too.

   This is nice because you can even do something like:

 (run (cond (foo bar)
(baz basil)))

 - However, things that handle ports aren't thunks... they're callbacks
   that take an argument of whatever port it is.  Hence, making a thunk
   doesn't make sense.  But I still want an easy way to provide the
   clean appearance of inline code.  So (wrap-apply) passes along
   whatever arguments.

   You can't pass certain syntactic forms to (apply), for example cond
   above, so it's not as desirable generally.

> First it looks like a delayed call, so why not use force/delay.

It might be 

Re: Announcing 8sync: an asynchronous programming language for Guile

2015-12-05 Thread Amirouche Boubekki

Le 2015-12-05 15:58, Christopher Allan Webber a écrit :

Amirouche Boubekki writes:


*** `tdelta` is not useful.


tdelta is used so the the agenda knows to put it a future time from the
current execution of the agenda.



I wanted to write that it's only a shorcut:

```
(define tdelta make-time-delta)
```



Re: Announcing 8sync: an asynchronous programming language for Guile

2015-12-05 Thread Amirouche Boubekki

Le 2015-12-05 15:58, Christopher Allan Webber a écrit :

Amirouche Boubekki writes:


* %8sync

This is the main macro, here is it's definition:

```
(define-syntax-rule (%8sync async-request)
   (propagate-%async-exceptions
(abort-to-prompt (current-agenda-prompt) async-request)))
```

I'm wondering whether (current-agenda-prompt) is useful.
I think the code will abort to the prompt of the current dynamic
context. So except if there is multiple agenda in the same thread,
it's not useful.


You're right that this is the context in which this becomes useful.  I
might have composed agendas at some point.  I'm not sure.


It's comparable to the way I define blocking procedures in async.scm

```
(define-public (read/ sock)
   (abort-to-prompt 'loop async-request
```


Right, that means that 'loop is always for "the agenda", and there will
always be one.


where `async-request` is in `async.scm`:

```
(lambda (cc) (loop-add-reader sock (lambda () (cc (read sock)
```

It's the way `async.scm` does blocking calls (and *only* blocking
calls).  `read/` and its `async-request` is missing catch around
`read` and something like `propagate-%async-exceptions`.


8sync doesn't block though.  Its use of select means you only need to
get information once it's available.

The code you have here will block other code that is available to run
while it's waiting for code.


I wrote "blocking" code in the sens that it is a call that blocks
when the port is not ready. In this case `read` is called
when the port is ready via the lambda registered as callback
with `loop-add-reader` which is called via select only when the port is 
ready.


It's similar to 8sync code, except there is not later dispatch like
in setup-async-request. Instead it's directly registers in the handler
of call-with-prompt.

The argument of the prompt is:


(lambda (cc) (loop-add-reader sock
   (lambda ()
 (cc (read sock)


Which is called by the handle of call-with-prompt as callback:

```
(call-with-prompt 'loop
  loop-run-once
  (lambda (cc callback) (callback cc)
```

Here cc is the continuation of the prompt handler.

tldr: There is certain number of proc that call each other
  in some order for the better good :)



8sync has two types of async-request:

** run-requests, which implements kind of a *coroutine* behavior.

It pause the execution of the current procedure and schedule
the provided lambda to be run soonish; This doesn't exists in
async.scm. The only thing useful this can do, is break the callstack
to allow deeper recursion.


That's not true.  See the problems of "callback hell" people get into 
in

node.js.  8sync mitigates this.


Yes, but this must be mitigated only for calls that would block without
select.


As for the callback stack, it does get broken that's true... but that's
why 8sync gives you copies of all the stacks that were recursively
called as it walks back through its ~futures upon some exception.


This is nice.



I realize I disagreed with a lot of what you said, but a lot of the
things you challenged are intentional designs in 8sync, not accidents.

I do appreciate the feedback though, it helped me clarify some of the
design decisions in 8sync, which will be useful for docs-writing!



Thanks for taking the time to respond it helps better understand.




Re: Announcing 8sync: an asynchronous programming language for Guile

2015-12-05 Thread Amirouche Boubekki

Le 2015-12-04 03:47, Amirouche Boubekki a écrit :


   Le 2015-12-04 03:15, Amirouche Boubekki a écrit :

   ```
   (define (read/ sock)
 (abort-to-prompt 'loop (lambda (cc)
  (loop-add-reader sock (lambda () (cc 
(read

   sock)))
   ```



   This is a mistake, it *must* be a macro



This will only help with debugging but not catching error and
dealing with them at runtime ie. it doesn't propagate the exception
but it can be done and requires a form similar to 
propagate-%async-exceptions.


TBH the code still seems complex maybe complicated. FWIW here is
what I think right now. Be warned that everything should be taken
with a grain of salt.

* Agenda

** The canonical callback based event loop API is not visible enough

It should be obvious coming from outside Guile world what/where
is the event loop. As such, agenda doesn't seem like a good name.

** Agenda has both `schedule` and `queue`

For a proof of concept, queue/schedule is not useful to demonstrate
the purpose of eightsync as it's an optimization.

** `(current-agenda-prompt)`

No need to throw, there should always be a current agenda.

* 

Schedule should be in its own file. Also, in place of:

```
(define-record-type 
  (make-schedule-intern segments)
  schedule?
  (segments schedule-segments set-schedule-segments!))
```

I prefer:

```
(define-record-type 
  (%make-schedule segments)
  schedule?
  (segments schedule-segments-ref schedule-segments-set!))
```

Use of `*-ref` and `*-set!`.

Or better: `(define-record-type*  segments)` (actually I
think this macro should be in Guile, since it much easier to
introduce  to new devs).

** `time` procedures have equivalent in Guile

*** `tdelta` is not useful.

* ``

** `run-it`

It's sound like it's a `(loop-call-soon callback #:optional (delay 0))`
procedure.

Instead it's a `(make-run-request proc #:optional time)`.

It's never used.

I'd rather to use a `delay`, and let the devs compute the correct delay,
when they wants to run something at an absolute time to limit the
proliferation of sugar procedure in the library.

*** `(wrap e ...)` and `(wrap-apply body)`

I'm pretty sure that `wrap` can be written using `wrap-apply`. This 
looks

suspicious for several reasons.

First it looks like a delayed call, so why not use force/delay.

Also wrap-apply is never used.

I think it's not schemey to hide a lambda this way, especially 
`wrap-apply`

which breaks lexical scope.

`wrap` is used with `(make-run-request proc time)` in `run`, `run-at`
and `run-delay`, e.g.:

```
(define-syntax-rule (%run-delay body ... delay-time)
  (%run-at body ... (tdelta delay-time)))
```

Again, `run` and others are building a datastructure not registering
a callback so the naming is not good.

* `(make-port-request port #:key read write except)`

In `async.scm` I don't need to create a datastructure to subscribe to 
select events.


** `port-request` defined at L452 is never used

* %8sync

This is the main macro, here is it's definition:

```
(define-syntax-rule (%8sync async-request)
  (propagate-%async-exceptions
   (abort-to-prompt (current-agenda-prompt) async-request)))
```

I'm wondering whether (current-agenda-prompt) is useful.
I think the code will abort to the prompt of the current dynamic
context. So except if there is multiple agenda in the same thread,
it's not useful.


It's comparable to the way I define blocking procedures in async.scm

```
(define-public (read/ sock)
  (abort-to-prompt 'loop async-request
```

where `async-request` is in `async.scm`:

```
(lambda (cc) (loop-add-reader sock (lambda () (cc (read sock)
```

It's the way `async.scm` does blocking calls (and *only* blocking 
calls).
`read/` and its `async-request` is missing catch around `read` and 
something

like `propagate-%async-exceptions`.

8sync has two types of async-request:

** run-requests, which implements kind of a *coroutine* behavior.

It pause the execution of the current procedure and schedule
the provided lambda to be run soonish; This doesn't exists in
async.scm. The only thing useful this can do, is break the callstack
to allow deeper recursion.

** port-requests, which implements imperative asynchronous calls of 
blocking operations


** %8sync usage example

```
(%8sync (%run (handle-line socket ready-line username)))
```

Where %run is a macro that implements exception catch,
complementary to `propagate-%async-exceptions`.

** Last note

This doesn't look nice:

```
(define (ports->procs ports port-map)
  (lambda (initial-procs)
(fold
 (lambda (port prev)
   (cons (lambda ()
   ((hash-ref port-map port) port))
 prev))
 initial-procs
 ports)))
```

then:

```
   ((compose (ports->procs
  read-ports
  (agenda-read-port-map agenda))
 (ports->procs
  write-ports
  (agenda-write-port-map 

Re: Announcing 8sync: an asynchronous programming language for Guile

2015-12-03 Thread Amirouche Boubekki

Héllo,


I've done some exploration regarding this topic; I think it might of 
interest or it's very naive.


It goes like this:

``` scheme

(define (loop-run-forever)
  (while #true
(call-with-prompt 'loop
  loop-run-once
  (lambda (cc callback) (callback cc)

```

`loop-run-once` does the `do-select` thing and call scheduled task. Then 
we only need to wrap blocking calls inside `abort-to-prompt`, here an 
example with `read`:


```
(define (read/ sock)
  (abort-to-prompt 'loop (lambda (cc)
   (loop-add-reader sock (lambda () (cc (read 
sock)))

```

`loop-add-reader` is procedure that register a callback against `select` 
to restart the computation where it was left it's equivalent to 
`port-request-read` machinery.



I attached an example server, the client is vanilla imperative code. 
Also, it doesn't implement exception propagation.



I don't understand the point of %8sync macro when all blocking calls can 
be expressed directly in terms of abort-to-prompt.



HTH
(setlocale LC_ALL "")

(define sock (socket PF_INET SOCK_STREAM 0))
(connect sock AF_INET INADDR_LOOPBACK 12345)

(pk sock)
(write "héllo world" sock)
(write "you are free" sock)
(close sock)
(define-module (plain))

(use-modules (srfi srfi-9))  ;; records
(use-modules (srfi srfi-9 gnu))  ;; set-record-type-printer! and set-field

;;;
;;; plain records
;;;
;;
;; macro to quickly define records
;;
;;
;; Usage:
;;
;;   (define-record-type  seats wheels)
;;   (define smart (make-abc 2 4))
;;   (car-seats smart) ;; => 2
;;
;; Mutation is not done in place, via set-field or set-fields eg.:
;;
;; (define smart-for-4 (set-field smart (seats) 4))
;; 

(define-syntax define-record-type*
  (lambda (x)
(define (%id-name name) (string->symbol (string-drop (string-drop-right 
(symbol->string name) 1) 1)))
(define (id-name ctx name)
  (datum->syntax ctx (%id-name (syntax->datum name
(define (id-append ctx . syms)
  (datum->syntax ctx (apply symbol-append (map syntax->datum syms
(syntax-case x ()
  ((_ rname field ...)
   (and (identifier? #'rname) (and-map identifier? #'(field ...)))
   (with-syntax ((cons (id-append #'rname #'make- (id-name #'rname 
#'rname)))
 (pred (id-append #'rname (id-name #'rname #'rname) #'?))
 ((getter ...) (map (lambda (f)
  (id-append f (id-name #'rname 
#'rname) #'- f))
#'(field ...
 #'(define-record-type rname
 (cons field ...)
 pred
 (field getter)
 ...))

(export define-record-type*)
(re-export set-record-type-printer!)
(re-export set-field)
(use-modules (rnrs bytevectors))
(use-modules (ice-9 rdelim))


(define sock (socket PF_INET SOCK_STREAM 0))
(bind sock (make-socket-address AF_INET INADDR_ANY 12345))
(listen sock 128)
(define inbound (accept sock))

(define-public (string->scm string)
  (call-with-input-string string
(lambda (port)
  (read port

(define (read-message port)
  (let next ((char (read-char port))
 (out '()))
(if (eq? char #\0)
(list->string (reverse out))
(next (read-char port) (cons char out)



Re: Announcing 8sync: an asynchronous programming language for Guile

2015-12-03 Thread Amirouche Boubekki

Le 2015-12-04 03:15, Amirouche Boubekki a écrit :


```
(define (read/ sock)
  (abort-to-prompt 'loop (lambda (cc)
   (loop-add-reader sock (lambda () (cc (read
sock)))
```


This is mistake, it should be a macro, so that, I think, even if the 
callstack displays the `loop-run-forever` and `loop-run-once` jazz, it 
still appears that the error happens where the blocking/async macro 
read/ was used.




Re: Announcing 8sync: an asynchronous programming language for Guile

2015-11-29 Thread Ludovic Courtès
Christopher Allan Webber  skribis:

> Christopher Allan Webber writes:
>
>> ... and the complicated-number-code will launch asynchronously, but wake
>> back up the appropriate function appropriately.  You can also set timed
>> events, read and write to ports asynchronously, and etc.  It has a nice
>> non-blocking loop, and personally I've found it to be a delight to use.
>
> There's one potential long-term caveat to this (maybe?), which is that
> the way this achieves nice asynchronous communication is by working hand
> in hand with guile's (select) statement, which seems to only work for
> socket type ports and file type ports I think?

Yes, ‘select’ is only for “file ports”, which means ports backed by a
file descriptor.  I guess 8sync will have to provide a higher-level
interface on top of that?

Ludo’.




Re: Announcing 8sync: an asynchronous programming language for Guile

2015-11-29 Thread Christopher Allan Webber
Ludovic Courtès writes:

> Christopher Allan Webber  skribis:
>
>> Christopher Allan Webber writes:
>>
>>> ... and the complicated-number-code will launch asynchronously, but wake
>>> back up the appropriate function appropriately.  You can also set timed
>>> events, read and write to ports asynchronously, and etc.  It has a nice
>>> non-blocking loop, and personally I've found it to be a delight to use.
>>
>> There's one potential long-term caveat to this (maybe?), which is that
>> the way this achieves nice asynchronous communication is by working hand
>> in hand with guile's (select) statement, which seems to only work for
>> socket type ports and file type ports I think?
>
> Yes, ‘select’ is only for “file ports”, which means ports backed by a
> file descriptor.  I guess 8sync will have to provide a higher-level
> interface on top of that?
>
> Ludo’.

Yes, it's actually already kind of extensible (and polling is already an
option in the loop)... though I'm not sure, what kind of things is
(select) insufficient for?  Databases usually expose some sort of port
interface, though Squee doesn't use it, for instance.

I guess maybe stuff like interfacing with GTK might be insufficient, but
I don't know.

Anyway, it seems like a lot can be done with (select).  The main concern
is, if other things aside from (select) are needed, can they be
composed?

For now, I'm forging ahead with (select)... luckily in Unix, many things
are backed by a file descriptor, including sockets... :)



Re: Announcing 8sync: an asynchronous programming language for Guile

2015-11-29 Thread Ludovic Courtès
Christopher Allan Webber  skribis:

> It makes significant use of delimited continuations.  You can do things
> like this:
>
>   (define (my-number-talker)
> (format #t
>   "Oh boy, looks like we got back ~a!\n"
>   (%sync (%run (+ 1 2 3 (complicated-number-code 38))
>
> ... and the complicated-number-code will launch asynchronously, but wake
> back up the appropriate function appropriately.  You can also set timed
> events, read and write to ports asynchronously, and etc.  It has a nice
> non-blocking loop, and personally I've found it to be a delight to use.

This is really cool!

Ludo’.




Announcing 8sync: an asynchronous programming language for Guile

2015-11-23 Thread Christopher Allan Webber
Hello all,

Some of you may remember the thread on this list about Guile needing an
asynchronous programming library, with a writeup from a conversation
David Thompson, Mark Weaver, guest star Andrew Engelbrecht, and I had at
LibrePlanet:

  https://lists.gnu.org/archive/html/guile-devel/2015-10/msg00015.html

Well! I've begun work on an asynchronous programming language called
"8sync" for Guile (pronounced "eight-sync", as in "eight-synchronous
communication" :))!  You can find it here:

  https://notabug.org/cwebber/8sync

A nice little logo here:

  http://dustycloud.org/gfx/goodies/8sync-protologo2.png

Hm, I need a nice website to go with that logo! :)

It makes significant use of delimited continuations.  You can do things
like this:

  (define (my-number-talker)
(format #t
  "Oh boy, looks like we got back ~a!\n"
  (%sync (%run (+ 1 2 3 (complicated-number-code 38))

... and the complicated-number-code will launch asynchronously, but wake
back up the appropriate function appropriately.  You can also set timed
events, read and write to ports asynchronously, and etc.  It has a nice
non-blocking loop, and personally I've found it to be a delight to use.

(Also should I be calling that thing (%sync) or (8sync)?  The jury is
out, so in the meanwhile, it's an alias!)

Anyway, there's a lot to be done... I'm not at a 0.1 release quite yet,
but am rapidly approaching it.

If you're interested in giving it a whirl, there's an IRC bot that ships
with it already in the demos/ directory.  Oh yeah, did I mention that
this makes use of the cooperative REPL system in Guile?  This means you
can *live hack your asynchronous code*.  Pretty cool!  (As such, we've
got a little guest in #guile right now named "syncbot"...)

More to come soon, including documentation, web programming examples, an
actor model implementation layered on top, and more functional
programming utilities, including maybe an Elm-like time traveling
debugger.  (There's currently some mutation under the hood, but all of
it can be refactored to be purely functional... with the exception of a
parameter that's used to find the current agenda.  Even that though,
I'll be writing code so you can schedule explicitly to the agenda
shortly if you really are upset by that one impurity.  Sure makes doing
%sync / 8sync calls nice though...)

Anyway, I'm having a ton of fun with this project.  Give it a
try... maybe you will too!

 - Chris



Re: Announcing 8sync: an asynchronous programming language for Guile

2015-11-23 Thread Christopher Allan Webber
Christopher Allan Webber writes:

> ... and the complicated-number-code will launch asynchronously, but wake
> back up the appropriate function appropriately.  You can also set timed
> events, read and write to ports asynchronously, and etc.  It has a nice
> non-blocking loop, and personally I've found it to be a delight to use.

There's one potential long-term caveat to this (maybe?), which is that
the way this achieves nice asynchronous communication is by working hand
in hand with guile's (select) statement, which seems to only work for
socket type ports and file type ports I think?  Mark Weaver said he'd
think if there were other options.  I've briefly scanned the relevant C
code but I'm not really sure if there's any way we can expose a more
flexible system or not.

Anyway, socket and file ports cover quite a lot of async stuff, so
that's a great step already!

 - Chris