web-dev-qa-db-ja.com

Clojure適用vsマップ

関数からシーケンス(foundApps)が返され、関数をそのすべての要素にマップしたいと思います。何らかの理由で、applycountはシーケンスで機能しますが、mapは機能しません。

(apply println foundApps)
(map println rest foundApps)
(map (fn [app] (println app)) foundApps)
(println (str "Found " (count foundApps) " apps to delete"))))

プリント:

{:description another descr, :title apptwo, :owner jim, :appstoreid 1235, :kind App, :key #<Key App(2)>} {:description another descr, :title apptwo, :owner jim, :appstoreid 1235, :kind App, :key #<Key App(4)>}
Found 2 apps to delete for id 1235

したがって、applyはシーケンスに対して問題なく機能するように見えますが、mapは機能しません。私はどこで愚かですか?

34
James Massey

おそらくあなたはmapの怠惰に見舞われているでしょう。 (mapは、一部のコードが実際にその要素を使用する場合にのみ実現されるレイジーシーケンスを生成します。それでも、実現はチャンクで行われるため、シーケンス全体をウォークしてすべてが実現されたことを確認する必要があります。) map式をdorunでラップしてみてください。

(dorun (map println foundApps))

また、副作用のためだけに行っているので、代わりにdoseqを使用する方がクリーンな場合があります。

(doseq [fa foundApps]
  (println fa))

(map println foundApps)はREPLで問題なく機能するはずであることに注意してください。強制されていないコードのどこかから抽出したと思います。厳密な(つまり、怠惰ではない)doseqとそのような違いはなく、どのような状況でも引数シーケンスをたどります。また、doseqは値としてnilを返すことに注意してください。それは副作用にのみ有効です。最後に、コードからrestをスキップしました。 (rest foundApps)を意味している可能性があります(タイプミスでない限り)。

また、(apply println foundApps)はすべてのfoundAppsを1行に出力しますが、(dorun (map println foundApps))foundAppsの各メンバーを独自の行に出力することに注意してください。

34
Michał Marczyk

この投稿には欠けている簡単な説明があります。抽象関数Fとベクトルを想像してみましょう。そう、

(apply F [1 2 3 4 5])

に変換されます

(F 1 2 3 4 5)

つまり、Fはせいぜい可変個引数でなければなりません。

一方

(map F [1 2 3 4 5])

に変換されます

[(F 1) (F 2) (F 3) (F 4) (F 5)]

つまり、Fは単一変数であるか、少なくともこのように動作する必要があります。

mapは実際にはベクトルではなく遅延シーケンスを返すため、型には微妙な違いがあります。しかし、簡単にするために、私はそれが許されることを願っています。

25
rishat

少し説明が役立つかもしれません。一般に、applyを使用して、一連の要素を関数の引数のセットにスプラットします。したがって、いくつかの引数に関数を適用するということは、1回の関数呼び出しでそれらを引数として関数に渡すことを意味します。

Map関数は必要な処理を実行し、入力の各要素を関数に接続して出力を保存することにより、新しいseqを作成します。ただし、それは怠惰に行われるため、値は実際にリストを反復処理したときにのみ計算されます。これを強制するには、(doall my-seq)関数を使用できますが、ほとんどの場合、これを行う必要はありません。

印刷やデータベースへの保存などの副作用があるためにすぐに操作を実行する必要がある場合は、通常、doseqを使用します。

したがって、すべてのアプリに「foo」を追加するには(文字列であると想定):

(map(fn [app](str app "foo"))found-apps)

または無名関数にshorhandを使用する:

(マップ#(str% "foo")が見つかりました-アプリ)

同じことを行いますが、すぐに印刷するには、次のいずれかを使用します。

(doall(map#(println%)found-apps))

(doseq [app found-apps](println app))

10
rosejn