Fork me on GitHub
#missionary
<
2021-08-03
>
leonoel08:08:16

if you want to use a promise in a flow, first turn it into a task and then use ap and ?

(defn promise->task [p]
  (fn [s f] (.then p s f) #()))

(defn task->promise [t]
  (js/Promise. t))

(m/ap (.blob (m/? (promise->task (.fetch js/window "flowers.jpg")))))

nivekuil13:08:15

is it possible to do this sort of promise/completablefuture to task conversion automatically?

leonoel13:08:47

It could have been possible if tasks relied on a specific clojure protocol, but I rejected this idea because : * I wanted the base primitives to be dependency-free * I don't like implicit conversions in general, especially when the semantics don't fully match

ribelo08:08:19

Up to this point it's easy, but to run fetch in background I have to use reactor?

leonoel08:08:59

no, just run it

leonoel08:08:45

what do you mean by in background ?

ribelo08:08:35

quick core.async example

ribelo08:08:40

(defn <http
  [{:keys [method url opts] :or {opts {}}}]
  (go (case method
        :get  (<p! (-> (.get axios url (->js opts)))))))

ribelo08:08:01

go macro is simple and stupid

leonoel08:08:34

missionary encourages structured concurrency, so it feels more constrained

leonoel08:08:27

go is unstructured, no supervision

leonoel08:08:48

functional composition of effects essentially builds a supervision hierarchy and it is a good default because errors have a natural path and you can propagate cancellation

leonoel08:08:23

if for some reason you need to escape the supervision tree, you can still use the low-level API with promises or any other communication channel

ribelo08:08:52

I'm not at my computer right now so I have no way to check. I understand that ap simply returns a function that I can run? Great.

leonoel09:08:16

the low-level API of flow is not straightforward, but tasks are plain old CPS so maybe start with that

Daniel Jomphe13:08:08

You make me curious. Has anyone ever claimed that missionary could be used favorably in all or most situations where we normally reach out for core.async?

jjttjj13:08:53

@danieljomphe I love missionary and am excited to see that it's getting more popular in the Clojure community. I think core.async and missionary have subtly different goals. Core.async, being a CSP implementation, will be better when your problem is best modelled as communication sequential processes, that is, when there is a lot of separate things going on and there is a very particular way you need to manage their interaction, particularly when this interaction involves some sort of state. I've found core.async a more natural fit when my problem is a somewhat complicated state machine. However, it's lower level than missionary and can be more painful to manage. Missionary really shines when your process isn't super stateful inherently and is more about reacting to new inputs. I could be wrong on this though and I'm looking forward to other answers. A counterpoint is that the missionary examples (happyeyballs and retry/backoff) could definitely have a heavily stateful implementation but these are solved cleverly with the missionary constructs instead. So it might be true that state machines are useful less often then they might seem and are reached for too quickly for many problems

👍 6
Daniel Jomphe14:08:08

Thanks a lot to you both. Dustin's improvements to the Readme are useful, as jjttjj's own reflections. This all suggests to me that reaching to missionnary should be my first reflex for most situations. I'll be on the hunt for every beginner-level, bite-sized code example out there in the future. I'll also keep a very close watch on Hyperfiddle's photon and zero projects and whatever else comes out of this shop. 🙂

Dustin Getz14:08:43

Maybe I will do another pass on that readme this week, Leo gave good feedback which is not incorporated in that sketch (which was not meant to be seen yet)

Daniel Jomphe14:08:40

Thanks a lot, this is very valuable!