Skip to content

Instantly share code, notes, and snippets.

@remexre
Last active June 12, 2017 18:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save remexre/e8b8f5ae2aef47ebb18473e43b40335e to your computer and use it in GitHub Desktop.
Save remexre/e8b8f5ae2aef47ebb18473e43b40335e to your computer and use it in GitHub Desktop.
(defn-async foo (bar)
; x and y are "awaited" in parallel
; This is the equivalent of Promise.all in JS.
; Note: this means x *cannot* be used in y.
(await (x (some-async-function))
(y (other-async-function bar)))
; async-return is Promise.resolve in JS-speak, or the
; monad `return` function in Haskell-speak.
(async-return (+ x y)))
(defn-async quux ()
; This is how you use an async result in another async function.
(await (x (yet-another-async-function)))
(await (y (other-async-function x)))
(async-return (+ x y)))
(defn-async xyzzy ()
; async tail calls ofc allowed "raw"
(await (x (some-async-function)))
(last-async-function x))
@remexre
Copy link
Author

remexre commented Jun 12, 2017

Notes:

  • defn-async is a macro that handles await properly.
  • This means await is only "defined" inside defn-async blocks.
  • Also, using await as a function name inside a defn-async will cause fun.
  • lambda is to defn as async is to defn-async
    • I might call async lambda-async instead, just to make it more explicit.
  • This gets kind of awkward when Either/Result is brought into the picture...
    • Async is basically a monad with an additional (Async a, Async b) -> Async (a, b) operation
      • For n-tuples though, but there's not a pretty way to write that in Haskell-notation
    • Either/Result is definitely a monad
    • Wait, I just thought of another way to try to explain monads
    • You might try to kill me if I bring monad transformers into the language
      • A lambda-monads/defn-monads form would make this simpler...
      • Basically, the problem is that there's no general way to do (Monad m1, Monad m2) => m1 (m2 a) -> m2 (m1 a), so we can't do Async (Either err ok) -> Either (Async err) (Async ok) without knowing whether the Either is an error or not, and since we're not a lazy language, that basically would involve evaluating the whole thing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment