Is core.async contrary to the principles of Clojure?

I have seen many Clojure programmers, enthusiasts about the new core.async library, and although it seems very interesting to me, it is not easy to see how it complies with Clojure principles, so I have the following questions:

  • It uses mutable state everywhere, since function names assume the presence of an exclamation mark, for example alt !, put !,>!, And others. If you put or take a value from a channel, that channel will be replaced. Isn't that against Clojure's philosophy of preferring immutable data structures, pure functions, etc.? Or is core.async used to be used only where mutable things cannot be avoided at all?
  • Since "go" is a macro (thus changing the structure of the code) and provides "<!" used directly in the go block, it is impossible to use "<!" inside another function, for example:

    (defn take-and-print [c] (println (<! c))) (def ch (chan 1)) (>!! ch 123) (go (take-and-print ch)) Assert failed: <! used not in (go ...) block 

    It seems to me that this prevents simplicity and convenience. Why is this not a problem?

  • Perhaps because of the previous two problems, a lot of code with core.async uses lower-level constructs such as loop / recur instead of map / filter / reduce. Isn't that a step back?

Where will I miss the point?

Thanks in advance.

+42
clojure core.async
Aug 13 '13 at 0:09
source share
6 answers

The first problem is yes, the main operations are side effects. However, there are no problems with the channels, usually associated with mutable links, since they do not constitute a β€œplace” - the channels are opaque, you cannot check them, in fact you cannot even ask whether the channel is closed or not outside of reading zero.

The second problem - to do something more than petty income, means transforming the entire program. This is a compromise, and I consider it reasonable. The composition level is channels that do not go to blocks, and they make up just fine.

Ultimately, you can easily perform Rx-style maps / filter / reduce operations on channels, and people have already done it.

+35
Aug 13 '13 at 0:34
source share

The limitation of the go macro (its locality) is also a feature: it ensures the locality of the source code for state operations.

+16
Aug 14 '13 at 14:50
source share
  • this is somewhat the opposite, Core.async can only be used on systems where immutability is the norm . Thus, the principles of Clojure allow you to use core.async rather than the reverse.

  • This restriction, also elsewhere in Clojure, limiting anonymous functions outside the % character seems to at least give the same idea. Not that finding another case of limitation makes it better, of course.

  • I did not see this myself, although it would be a step backwards if you tried to make simple code and cleared yourself when you expressed it in one form, and then expressed it in the way that it is. not this way...

+10
Aug 13 '13 at 0:34
source share

Rich Hickey said in a lecture on blip.tv that Clojure is "85% functional." I like to see core.async as part of the remaining 15%. Core.async is great for reliable user interaction among other things, which would be done with promises, delays and other things, most likely in a more confusing way.

+5
Aug 13 '13 at 9:16
source share

Each program consists of two parts: one part, which always contains non-talk data, spits out, etc. For this part, we know what core.async has, but the .async kernel has mutable things, but pay attention to two things. The state of the channels is mainly controlled by the library. What you give is what flowstate can be called. This means that when you put something like a channel, you do not expect to return to it or even change it.

Core.async is a pleasure to manage this part of your program. Otherwise, all the transformations and calculations of your data clojure try to give you good tools to do this functionally.

It seems to me that this prevents simplicity and convenience. Why is this not a problem?

There are two worlds: synchronization and asynchronous world. You can put things or take things from asynchronous wrold using! and take it! but others, then (and possibly some other functions), these worlds are separated from each other. clojure does not want to become completely asynchronous. Functions and data transformation are what you need to put together.

Perhaps, as a consequence of the previous two problems, a lot of code with core.async uses lower-level constructs such as loop / recur instead of map / filter / reduce. Isn't that a step back

An operation similar to these channels will be possible. Core.async is still young, and not all possible constructs and functions have been written yet.

But in the general case, if you have big data transformations, you really do not want to do them in the asynchronous world, you want them to be in a collection, and then throw something like a reduction structure on it.

The main thing to understand this, core.async is not a new standard, it is another thing that helps you in programming. Sometimes you need STM, sometimes agents, sometimes CSP, and clojure wants to provide you with all the options.

One of the reasons people love core.async is because it helps with some things that are really really hard to handle, such as callbacks.

+1
Jan 20 '14 at
source share

a possible solution to use (<! c) macro outside go can be made using a macro and its macro expansion time:

This is my example:

 (ns fourclojure.asynco (require [clojure.core.async :as async :refer :all])) (defmacro runtime--fn [the-fn the-value] `(~the-fn ~the-value) ) (defmacro call-fn [ the-fn] `(runtime--fn ~the-fn (<! my-chan)) ) (def my-chan (chan)) (defn read-channel [the-fn] (go (loop [] (call-fn the-fn) (recur) ) )) (defn paint [] (put! my-chan "paint!") ) 

And check this out:

 (read-channel print) (repeatedly 50 paint) 

I tried this solution in nested mode and also worked. But I'm not sure if this could be the right way.

-one
Oct 23 '13 at 9:23
source share



All Articles