LoginSignup
1
1

More than 1 year has passed since last update.

Juliaのdoブロック

Last updated at Posted at 2022-09-26

イントロ

ある関数gを引数として他の関数fに渡すというのは非常に便利な機能である。特に無名関数を渡すような使い方は頻繁に現れる。以下はmap関数の例である(fがmap, gがx->x^2)。

map(x->x^2, [1,2,3])

ただし、無名関数の部分が非常に長くなるとかなり煩雑で読み書きし難いコードになる。公式ドキュメントでは条件分岐を含むような関数をmapに渡す例が載っている([A,B,C]は何か適当なものを指してるだけ):

map(
    x->begin
       if x < 0 && iseven(x)
           return 0
       elseif x == 0
           return 1
       else
           return x
       end
    end,
    [A,B,C]
)

こういう関数を引数にとる関数を扱うための便利な機能としてdoブロックがある。それについてのメモ。

記法

まず、どういう記法かを書いてしまう。以下のような記法である。関数fは第一引数に関数を受け取れるものとする。このとき、

f(第一引数以外) do 無名関数の引数
    無名関数が行う処理 
end

とかくと、doの次の部分を引数にとり、その後のブロック内の処理を行う無名関数を作って、fに渡すというコードになる。たとえば、さきほどのmapの例なら以下のようになる。

例1
map([1,2,3]) do x
    x^2
end
例2
map([A,B,C]) do x
    if x < 0 && iseven(x)
        return 0
    elseif x == 0
        return 1
    else
        return x
    end
end

do a, bとすれば2個の引数abを受け取る無名関数が作れる。3個以上も同様。ただし、(a,b)と書くと、1つのタプルを受け取る関数になるので注意。

用法

map関数以外にもたくさんの用法がある。いくつかの便利な用例を書いておく。

安全なファイル処理

たとえば、ファイルを開いて何かを処理したあと必ずそれが閉じられるようにしておきたい場合があるだろう(毎度、直接open()としてあとでclose()を書くのではなくて。closeを書き忘れたりしそうじゃない?)。ここで、処理については任意の関数を想定しておきたい。つまり

io = open(...)
try
    ioに対する何らかの処理
finally
    close(io)
end

というようなことをしたいのだが、tryの中身は色々あり得る。毎回これらを書くのは面倒なので何とかしたいというわけである。このような場合には、処理部分を関数として受け取り、一連の処理を行う関数を作ればよいが、まさにdoブロックが活躍する場面になっている。

function open(f::Function, args...)
    io = open(args...)
    try
        f(io)
    finally
        close(io)
    end
end

として、

open("outfile", "w") do io
    ioに対する何らかの処理
end

とすればよい。ファイルの処理の部分はopen内に完全に隠されて、単にファイルに対して何をするかを普通のコードのように書けばよい。

Fluxの勾配計算

他の例として、Fluxという機械学習向けのJuliaのpackageにおける勾配計算の記法がある。モデルmがあり、それを使って関数l(損失関数とかを想定すればよい)を計算したうえで、Flux.params(m)に対して微分したいとする。このような場合、素朴にはFlux.gradient(()->l(hogehoge), Flux.params(m))とかなのだがlの部分は複雑になりうる。ここでlの部分をdoブロックを使って外に出しておけばどこまでが関数引数なのかわからなくなったりしない:

gradient(Flux.params(m)) do 
    l(hogehoge)
end

なお、gradientは「引数をとらない関数」を引数にとるので、doの後ろの引数の部分は空白になっている

参考

1
1
0

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
1
1