web-dev-qa-db-ja.com

core.asyncはClojureの原則に反していませんか?

多くのClojureプログラマーが新しいcore.asyncライブラリーに熱心に取り組んでいるのを見てきました。非常に興味深いようですが、Clojureの原則にどのように準拠しているかを確認するのに苦労しているので、次の質問があります。

  1. 関数名がalt!、put!、>!などの感嘆符を付けることで示唆するように、どこでも可変状態を使用します。チャネルに値を入力または取得すると、そのチャネルはインプレースで変更されます。不変のデータ構造、純粋関数などを優先するというClojureの哲学に反していませんか?または、core.asyncは、変更可能なものをまったく回避できない場合にのみ使用するように作成されていますか?
  2. 「go」はマクロであり(したがってコード構造を変更する)、「<!」を保証するためです。 go-blockで直接使用されている場合、「<!」を使用することはできません。このような別の関数の内部:

    (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
    

    これは単純さと構成可能性を妨げるように私には思えます。なぜ問題ないのですか?

  3. 前の2つの問題の結果として、core.asyncを使用する多くのコードは、map/filter/reduceの代わりにloop/recurなどの低レベルの構造を使用します。一歩後退していませんか?

どこにポイントがありませんか?

前もって感謝します。

42
aeuhuea

最初の懸念-はい、コア操作は副作用です。ただし、チャネルは「場所」を表さないため、通常は可変参照に関連する問題はありません。チャネルは不透明であり、検査することはできません。実際、チャネルが閉じているかどうかを照会することもできません。なし。

2番目の懸念-浅い歩留まり以上のことをすることは、プログラム全体の変革を意味します。これはトレードオフであり、合理的なものだと思います。構成のレベルは、ブロックではなくチャネルであり、それらは問題なく構成されます。

最後の懸念は、チャネルを介してRxスタイルのマップ/フィルター/リデュース操作を簡単に実行でき、人々はすでにそうしていることです。

37
dnolen

Goマクロ(その局所性)の制限も機能です。ステートフル操作のソースコードの局所性を強制します。

16
cgrand
  1. それはやや逆です、 Core.asyncは、不変性が標準であるシステムでのみ使用できます。。したがって、Clojureの原則は、逆ではなくcore.asyncを有効にします。

  2. これは制限であり、clojureの他の場所でも発生します。%記号で構成されていない無名関数の制限は、少なくとも同じ考えを示しているようです。もちろん、制限の別のケースを見つけることがそれをより良くするというわけではありません。

  3. 私はこれを自分自身で見たことがありませんが、単純でクリーンなコードを1つの方法で表現し、それを...その方法ではない方法で表現しようとすると、一歩後退します。 。

11
Arthur Ulfeldt

Rich Hickeyは、blip.tvの講義の1つで、Clojureは「85%機能的」であると述べました。 core.asyncを他の15%の一部として見たいと思います。 Core.asyncは、約束、遅延、その他のことによって、おそらくもっと厄介な方法で行われるであろう、とりわけ確実なユーザーインタラクションに最適です。

5
claj

すべてのプログラムには2つの部分があり、1つの部分は常に非機能トークデータであり、それを吐き出すなどです。この部分では、core.asyncがあることがわかっています。core.asyncには変更可能なものがあるのは当然ですが、2つのことに注意してください。チャネルの状態は、基本的にライブラリによって管理されます。あなたがそれに置くものは、何がフローステートと呼ばれるかもしれないかです。つまり、チャンネルのようなものを置いたときに、そこに戻ってくることや、変更することすら期待しないということです。

Core.asyncは、プログラムのこの部分を管理するのに最適です。残りの部分については、データのすべての変換と計算について、clojureは機能的にそれを行うための優れたツールを提供するために最善を尽くします。

これは単純さと構成可能性を妨げるように私には思えます。なぜ問題ないのですか?

同期と非同期の2つの世界があります。あなたはものを置くことができます、またはputで書かれた非同期からものを取り出すことができます!そしてとる!しかし、それ以外の場合(そしておそらく他のいくつかの機能)、これらは世界に分離されています。 Clojureは、完全に非同期の言語になることを望んでいません。関数とデータ変換は、構成可能である必要があるものです。

前の2つの問題の結果として、core.asyncを使用する多くのコードは、map/filter/reduceの代わりにloop/recurなどの低レベルの構造を使用します。一歩後退していませんか

そのようなチャンネルでの操作が可能になります。 Core.asyncはまだ若く、すべての可能な構成と関数がまだ作成されているわけではありません。

しかし、一般的に、非同期の世界で実際に実行したくない大規模なデータ変換がある場合は、それらをコレクションに入れてから、reducresフレームワークのようなものをスローします。

理解すべき主なことはこれです。core.asyncは新しい標準ではなく、プログラミングに役立つもう1つのことです。 STMが必要な場合もあれば、エージェントが必要な場合もありますが、CSPが必要な場合もあり、clojureはすべてのオプションを提供したいと考えています。

Core.asyncが好きな理由の1つは、コールバックの処理など、他の方法では処理が非常に難しいものに役立つためです。

2
nickik