chansey97
2021-1-27 09:06:46

> Is this how you imagined it? (edited) @yilin.wei10 Yes. That is event-loop, right.


chansey97
2021-1-27 09:07:49

> you’re imposing languages to do it the javascript/node way rather than using threads/coroutines/whatever the language provides. @jestarray What I have to say is that “async/await in Javascript” and “coroutine (or generator) in Racket” have equivalent capabilities, though their implementation are different. Both can convert an unblocking operation to a blocking operation (at least from the perspective of syntax). But future&promise mechanism can do <https://stackoverflow.com/questions/35612428/call-async-await-functions-in-parallel|more than that>: await/yield only supports vertical composition. future supports vertical and horizontal composition (i.e. future-all, future-race) and it also supports error-handling. (Another advantage of future&promise is that they give a clear contract for asynchronous functions.)


chansey97
2021-1-27 09:08:36

> also gamedevs use threads to implement asynchronous operations all the time. I use rust for gamedev and everyone just uses threads. we have async await but its still iffy @jestarray Gamedev can use multi-threading indeed (it often depends on different game types and optimization strategies). But most games’ main thread has the following structure: ;; Graphic/UI thread (let loop(()) (update) ; &lt;--- logic code (draw) ; &lt;--- rending gameobject and UI (loop)) Imagine that, in the logic code (update), we invoke an async operation (which need access network) to get score and then refresh the UI. It can not block UI normal drawing.


samth
2021-1-27 14:09:03

If you want to, for example, read from a channel but not block if nothing’s available, you might use sync/timeout.


samth
2021-1-27 14:09:28

You might also want to use async-channel



yilin.wei10
2021-1-27 15:13:17

wrap-evt is similar to map.


yilin.wei10
2021-1-27 15:16:00

Does the example illustrate enough to answer your problems, or are there still issues which are unclear/you’re seeking answers for?


chansey97
2021-1-27 17:27:34

@yilin.wei10 I am not familiar with Racket evt. (sync/timeout 0 evt) seems to be able to convert a blocking operation to non-blocking operation (like unblocking socket), but I dont know how to encode my code above by Racket evt. What channel corresponds to ? promise? What wrap-evt corresponds to? then? Is there any one-to-one correspondence between Racket event and promise?


chansey97
2021-1-27 17:29:34

Could you demonstrate how to use evt to encode my code above? It would be nice if they can be combined with coroutine.


badkins
2021-1-27 18:19:52

Argh! I just fixed a bunch of bugs and made some refinements. The engine was playing really well just now, but failed to generate one particular move for my opponent, so when I entered their move, it thought it was illegal, and I had to resign a good position. Moving a queen to a1, so I probably have an off by one error :)


badkins
2021-1-27 18:39:03

Game is here. Letting Stockfish chew on it for a while showed my engine was up 1.37 points: 1. c3 e5 2. a3 Nf6 3. d4 exd4 4. Qxd4 Nc6 5. Qe3+ Be7 6. c4 O-O 7. Qd2 Bc5 8. Qd3 d6 9. b4 Bd4 10. Ra2 Be5 11. b5 Nd4 12. Nd2 a6 13. f4 Bxf4 14. Qxd4 Be5 15. Qd3 axb5 16. cxb5 Qd7 17. Ndf3 Re8 18. a4 Qe6 19. Ra3 d5 20. Nxe5 Qxe5 21. Qd2 Qe4 22. e3 Rxa4 23. Rxa4 Qxa4 24. Bb2 Re6 25. Bxf6 Rxf6 26. Qxd5 Rd6 27. Qc4 Qa1+


badkins
2021-1-27 18:39:20

My engine has no notion of “king safety” yet - obviously :)


chansey97
2021-1-27 18:41:19

> wrap-evt  is similar to map. But future then is more like bind , not map then : future a -&gt; (a -&gt; future b) -&gt; future b vs wrap-evt : evt a -&gt; (a -&gt; b) -&gt; evt b So unfortunately they are different thing. In other words, you can not do async operation in the callback of wrap-evt : (define (async-rpc op x) (match op ['A (thread (λ () (channel-put ch 11)))] ['B (thread (λ () (channel-put ch 22)))] ['C (thread (λ () (channel-put ch 33)))])) (wrap-evt ch (λ (v) ;; Where can I write the continuation code for the async result of (async-rpc 'A 1)? (async-rpc 'A 1) ))


samth
2021-1-27 18:51:41

I think you’d want either guard-evt or replace-evt


chansey97
2021-1-27 19:11:16

Could you give me some examples of using guard-evt and replace-evt? I don’t really understand the guard-evt and replace-evt in the document. Or is there any reference or paper about Racket events?

Moreover, this is just one problem of evt, another problem is that evt has no “future source” which can trigger the callbacks’ chain. For example: (define e (wrap-evt ch (λ (v) 1 ))) ;; (sync/timeout 1 e) ; this can trigger the e's callback, OK. ;; (sync/timeout 1 ch) ; but this can not trigger the e's callback! ;; So `ch` can not be thought of as a promise.


yilin.wei10
2021-1-27 19:24:56

yilin.wei10
2021-1-27 19:25:27

Do you mean you want the event to be memoized?


yilin.wei10
2021-1-27 19:27:55

When you mean coroutines, do you mean userland coroutines, or the ones already in Racket?


yilin.wei10
2021-1-27 19:30:44

I’ve possibly got the terminology wrong but Racket already has a form of preemptive scheduling through it’s threads. With events, these are “like” coroutines.


chansey97
2021-1-27 19:33:18

@yilin.wei10 > Do you mean you want the event to be memoized? I dont understand what you mean.

> When you mean coroutines, do you mean userland coroutines, or the ones already in Racket? userland coroutines (e.g. generator).


chansey97
2021-1-27 19:33:35

I just tried to use Racket events to simulate promise&future which like my code above and then I found a lot of problems. I think Racket currently may not have the equivalent mechanism like promise/future as Javascript.


chansey97
2021-1-27 19:34:18

In fact, promise&future can also support multithreading. (e.g. Scala ExecuteContext, C# TaskScheduler) For example, in C# you can do async operation (in another thread) to modify UI element by Task UITask= task.ContinueWith(() =&gt; { this.TextBlock1.Text = "Complete"; }, TaskScheduler.FromCurrentSynchronizationContext()); But it will take more efforts to achieve this kind of things in Racket.


yilin.wei10
2021-1-27 19:35:20

Uh, so futures and promises are ambiguous because the behaviour is not well-defined (you get a spectrum across different languages, lazy/eager, memoized/unmemo, default parallel/default not). Memoized is where the future is side-effecting and only runs once.


yilin.wei10
2021-1-27 19:36:33

so f.race(f)) == f


yilin.wei10
2021-1-27 19:36:52

semantically


chansey97
2021-1-27 19:37:05

Futures and promises are ambiguous, yes. For example, Javascript conflates future and promise. More detail, see http://dist-prog-book.com/chapter/2/futures.html


chansey97
2021-1-27 19:40:32

Despite the ambiguity, there is still a most common explanation of promise&future. That is > A Future is a read-only reference to a yet-to-be-computed value. > A Promise (or a CompletableFuture/Completer/etc.) is a single-assignment variable which the Future refers to.


yilin.wei10
2021-1-27 19:41:51

OK, but that has the same properties as a channel and a single read evt.


chansey97
2021-1-27 19:46:34

The problems of channel and evt , see https://racket.slack.com/archives/C09L257PY/p1611772879101400?thread_ts=1611680164.072800&amp;cid=C09L257PY and https://racket.slack.com/archives/C09L257PY/p1611774676102100?thread_ts=1611680164.072800&amp;cid=C09L257PY

@samth said they can be implemented by either guard-evt or replace-evt , but it has a bit difficult (for me).


samth
2021-1-27 19:50:30

@chansey97 My suggestion is that if you want to write concurrent programs in Racket, you should use threads. If you need to communicate asynchronously in some contexts, you should use sync/timeout, async-channel, etc. Futures and promises are an approach to concurrency, and Racket emphasizes a somewhat different approach.


chansey97
2021-1-27 19:56:24

I haven’t looked at asynchronous channel yet. I will look into it. The examples of @yilin.wei10 given earlier use synchronous channel.


yilin.wei10
2021-1-27 19:57:02

I don’t think I used a channel?


chansey97
2021-1-27 20:01:32

The behavior of a port like a channel.


yilin.wei10
2021-1-27 20:04:39

I’m extremely confused; but if it makes sense to you, that’s good.


chansey97
2021-1-27 20:16:35

I think if the concurrent programs do not involve the UI thread, there is no problem to use threads in Racket, because the form (thread ...) creates a “green” thread. But if they involve UI thread, then promise&future are very useful.


samth
2021-1-27 20:17:21

There are lots of existing GUI programs written in Racket (such as DrRacket). They make extensive use of threads.


samth
2021-1-27 20:18:23

The problem of not blocking the UI thread is important, but that means that you don’t want to use blocking operations there. Using threads is the idiomatic way to do asynchronous prorgramming in Racket, which is thus how you avoid blocking the UI thread.


chansey97
2021-1-27 20:20:41

I haven’t seen many Racket GUI programs. I think one way to avoid blocking the UI thread is using a big state-machine. Or using coroutine in UI thread (but promise&future can do <https://racket.slack.com/archives/C09L257PY/p1611738469097500?thread_ts=1611680164.072800&cid=C09L257PY|more than that>).


chansey97
2021-1-27 20:47:42

@yilin.wei10 In your example, the tcp port is more like asynchronous channel, not synchronous channel. It is my fault sorry.


yilin.wei10
2021-1-27 22:04:47

No need to be sorry :slightly_smiling_face: @chansey97, as long as it helps your understanding, it’s all good.


badkins
2021-1-28 00:21:17

Oh, this was interesting. I just played someone on http://lichess.org\|lichess.org, and even though the engine could have mated in one move, it just kept gobbling up pieces. This was due to two factors: 1) it examines tactical moves, such as captures, before quiet moves, and 2) the alpha / beta infinite score was the same for a bunch of moves i.e. mate in 7, mate in 6, mate in 5, … , mate in 1, so it kept going down the path of capturing something instead of the shorter mate ! :) I just added/subtracted the depth from the min/max score to favor shorter mates, and that fixed it. The latest code is on the development branch, and should be reasonably good now: https://github.com/lojic/RacketChess/tree/development I’ll merge it after playing a few games on lichess.


jestarray
2021-1-28 06:07:28

can slideshow play gif/video files?