LoginSignup
5
7

More than 3 years have passed since last update.

Julia のパイプライン演算子と部分評価

Last updated at Posted at 2019-06-30

Juliaにはパイプライン演算子があり、一引数の関数であればチェーンして書くことができる。

[1, 4, 1, 3, 2] |> sort |> unique

しかし1引数関数しか書けないというのはいかにも不便。例えば、sortにはrevというフラグがあって、ソートの向きを変えられるのだけど、これも使えない。

もちろん、無名関数を使えばいいのだけど、ちょっと見通しが悪い。

[1, 4, 1, 3, 2] |> x -> sort(x, rev=true) |> unique

関数がcurry化というか部分評価できればいいわけなのだけど。ここでやりたいのは、第一引数以外の引数を与えて、第一引数だけを返す関数が作れればいいので、フルのcurry化というのもやりすぎ感ただよう。

ということでマクロの勉強を兼ねて部分評価するマクロを書いてみた。

add(x)

という式に対して、

(y) -> add(y, x)

という無名関数を返してやればいいわけだ。

macro partial(x)
    if typeof(x) == Expr
        if x.head == :call
            name = x.args[1]
            rest = view(x.args, 2:length(x.args))
            return esc(quote
                (y) -> $name(y, $(rest...))
            end)
        end
    end
    return x
end

このマクロは、引数が関数呼び出し型の式になっていた場合に、第一引数に引数を挿入する無名関数を返す。それ以外のときはとりあえず、受け取った式をそのまま返している。

このマクロを使うと、上のサンプルはこんなふうに書ける。

[1, 4, 1, 3, 2] |> (@partial sort(rev=true)) |> unique

文字数的には無名関数を使ったほうが短いぐらいなのだけど、新しい変数を導入しなくていいという点だけはこちらのほうがマシかな。

それにしてもJuliaのマクロ、ASTが直接いじれるのはいいけど、書きにくいなあ。。マクロに限らず、パターンマッチが貧弱だからか。この辺、強化されてほしい。

追記

2019/9/15 こちらもエスケープが足りていなかった。追加した。

また、filterなどの場合は第一引数ではなく、第二引数を置き換えたい。
プレースホルダーマクロを使えばいずれの場合でも、

[1, 4, 1, 3, 2] |> (@ph sort(_, rev=true)) |> unique

のように書けるので、こちらのほうがいいかもしれない。

5
7
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7