Arantium Maestum

プログラミング、囲碁、読書の話題

lazy-seqでmapを書いてみる?

「?」が付いていることに注意していただきたい。

実際に書いてみるまでは、正直なめていた。

というのも、まずは(map inc (range 10))というような書き方・使い方を想定していたのだ。

一つの関数と一つのシーケンスを引数として、シーケンスに含まれる値に関数を適用した値の連なりを返す、というもの。(map inc (range 10))だとしたら結果は1〜10までのリスト。

しかし、よく考えてみると、そもそも私自身、今まで何回も(map vector [1 2 3] [4 5 6])のような使い方もしてきた。ちなみにこの式の結果は([1 4] [2 5] [3 6])であり、Pythonzip関数と同じ挙動になる。

つまり、複数のシーケンスを引数として受け取れるのだ。それを踏まえてmapを書くとしたら以下のような感じか。

(defn my-map [f col & other-cols]
  (let [cols (con col other-cols)]
    (if (some empty? cols)
      ()
      (lazy-seq 
        (cons (apply f (for [c cols] (first c))) 
              (apply my-map f (for [c cols] (rest c))))))))

とりあえず関数一つと、一つ以上のシーケンスが引数でリストを返す。各シーケンスから第一要素を取り出すために(for [c cols] (first c))、そして第二要素以降のリストを次のmy-mapに回すために(for [c cols] (rest c))を使っている。

まあこんなものかな?と思って定義を読んでみる。

Returns a lazy sequence consisting of the result of applying f to the set of first items of each coll, followed by applying f to the set of second items in each coll, until any one of the calls is exhausted. Any remaining items in other colls are ignored. Function f should accept number-of-colls arguments. Returns a transducer when no collection is provided.

最後のはなんだ?

ググってみる。

Transducers are Coming — Cognitect Blog

Clojure - Clojure 1.7 is now available

Some trivial examples of using Clojure Transducers - An Ostler in IT

・・・transducer?知らん。(すっとぼけ

とは言わないまでも、一旦見なかったことにして置いておこうと思う。

軽く読んだ限りだと(map inc)という式自体が関数を返して、それをcompだとかで組み合わせてtransduce関数でコレクションに対して適用して使うっぽいが・・・ どうやって再現すればいいのかなんて現段階では見当もつかない。これを触るのはもう少し功夫を積んでからでいいだろう。

エントリの題に「?」が付いている所以である。