2019-10-05に投稿

Rustの並列処理を学ぼうぜ☆(^~^)?<その7>

<前回の記事>

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 カリー化 を特集する☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 軽く流せばいいのに……☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 中級者向けに書くぜ☆ 初心者はふるい落として、基本的な説明を省いて 用語をどんどん使っていくぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 コンピューターが勝手に カリー化 してくれるんだから、人類は黙って 多変数関数 使ってればよくない?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 簡単なものを使って 例えよう☆」

2 + 3

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑これは☆、」

3 + 2

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑こう書いても同じだが☆、」

x + y

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑変数 x、 y はどこかのタイミングで決まるとしよう☆ これを Function で書いてみよう☆」

add( x, y )
{
    x + y
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑これは 足し算記号に add という名前を付けただけの、あんまり嬉しさもない簡単なやつだぜ☆」

= add( 2, 3 )
= 5

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑こうなるのは 分かると思う☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 カリー化しようぜ☆」

20191005comp18a1b1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 引数が複数ある、または、返り値が複数ある 、そんな Function を、
引数が1つ、かつ、返り値は関数が1つ な Higher-order function に変えるのがカリー化だぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 引数が複数ある Function が どうやって 引数1つになるんだぜ☆?」

20191005comp18a1b2.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑Functionに 変数を覚えさせておけるようにして、
その Function を、さらに別の Function の中で呼び出せばいいわけだぜ☆」

apple( x )
{
    banana( y )
    {
        x + y
    }
}

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑カリー化すると apple は高階関数、 banana は一階関数になる☆
そして banana から見れば 変数x は 自由変数、 変数y は 束縛変数 に見えるぜ☆
しかし apple から見れば 変数x も y もともに束縛変数に見ることが お分かりいただけると思う☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 ふるい落とし始めたな☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 banana って クロージャー になってるんでしょ」

= apple( 2 )
= banana    # ただしxは2になっている。

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 apple は banana を返すことは お分かりいただけるであろうか?」

KIFUWARABE_80x100x8_01_Futu.gif
「 この banana は一階関数として使えるんじゃないか☆?」

= banana(3)
= 5

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 もちろん使えるぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 一度に使えるんじゃないの? 左結合 なんだから」

= apple( 2 )( 3 )
= banana( 3 )
= 5

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 まさにその通りだぜ☆」

= add( 2, 3 )
= 5

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑これは カリー化されていない Function で……☆、」

= apple( 2 )( 3 )
= 5

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑これは カリー化された Function だぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 カリー化 の操作方法は調べれば出てくるけど、 なぜカリー化を使いたいのか は調べても ヘタクソな説明 だけ出てくるのよ」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 なにが嬉しくて カリー化したFunction を作んの?」

20191005comp18a2b1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ↑ 入れ子 が作りやすくなる
上図は どんなに入れ子しても 引数は 一番内側の Function に渡される1個だぜ☆
一番シンプルな入れ子の例だが、 ここで注意してほしいんだが☆、」

20191005comp18a3.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 入り口が1つでも 中で複数個に分かれている ということはある ☆」

20191005comp18a3b1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「上図もやはり どんなに入れ子にしても 引数は1個だぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 分けわからん☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 図にすると 分けわからんが、式を書く人類にしてみれば……☆」

20191005comp18a2b1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 シンプルな入れ子にする手間だけで その分け分からん構造を 作れるんだぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 嬉しくないわね

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 まだある☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 自由変数がなく、計算が独立している かたまりを 小分け にしながら 振り分けることができる☆
自由変数がなく、計算が独立していると 何に効くかというと、絵に描いて説明してみよう☆」

20191005comp17a1.png

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 apple( x )( y ) みたいなやつは 自由変数を持っていないので コアに丸投げできるな☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 add( x, y ) も自由変数は持ってないわよ?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 apple( x )( y ) は banana( y ) みたいに小分けにして さらに振り分けることができる☆
どう小分けにするかは もっと低層の、機械寄りの、プログラム にやらせればいいだろう☆
add( x, y ) は 小分けにできない☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 ちぎって下請けに丸投げかだぜ☆ ガッカリだぜ☆」

= apple( 2 )( 3 )( 4 )
= banana( 3 )( 4 )
= cherry( 4 )
= 9

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 クロージャーの中に 変数が隠れてしまって 筆算の役には立たないわよ」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 それを Abstraction (アブストラクション;ラムダ抽象) と言う☆
計算は コンピューターがやるんで、人類は 式を間違わずに書くことだけ 集中しろだぜ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 下の計算結果が 上に帰ってこないと、上は次に進めないんだから、
下の処理を 別コアに ちぎって投げる意味なくない?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 これは 足し算 を例にしてるから うま味が 見えないんだぜ☆」

Core 1:
    = apple( 2 )( 3 )( 4 )
    = await banana( 3 )( 4 )
Core 2:
    = await banana( 3 )( 4 )
Core 3:
    = await banana( 3 )( 4 )
Core 4:
    = await banana( 3 )( 4 )

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 もしかすると banana は ちぎって配れるやつかもしれない☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 Java Script は シングル・スレッドのくせに NodeJSエンジン の forループ文、
ログの内容が順番バラバラに書かれている気がするんだが どうなってるんだぜ☆?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 ファイル書き出しが非同期なんだろ☆」

OKAZAKI_Yumemi_80x80x8_02_Syaberu.gif
「 返り値は1つしかないのに、どうやって 小分けにしてんの?」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 疑似コードで言うと、 Async、Async、Async、Async、Await all とかだな☆
Rust 言語には 2019年10月時点で Async/Await 構文が無いんで この話に入っていけない☆ どうしようもない☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 せっかく非同期処理なのに await で いちいち同期を取るのが 意味分かんないぜ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 複数の非同期コードを 配列かどこかに詰めて 一括して await できるやつが どっかにあるだろ☆」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 で、ほとんどのプログラム言語は カリー化 とか 人類が考えなくても
コンピューターが勝手に カリー化 に翻訳して実行してくれるだろ☆
気にせず add( x, y ) の形の Function を使えだぜ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 くそっ☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 カリー化を覚えたのなら、カリー化で書きたいだろ☆!」

KITASHIRAKAWA_Chiyuri_80x100x8_01_Futu.gif
「 関数コールは遅い☆
カリー化の真似して 見た目だけ合わせて書いたところで 無理くり合わせているだけで 実行速度が遅くなるだけかもしらん☆」

KIFUWARABE_80x100x8_01_Futu.gif
「 くそっ☆」

次の記事

ツイッターでシェア
みんなに共有、忘れないようにメモ

むずでょ

光速のアカウント凍結されちゃったんで……。ゲームプログラムを独習中なんだぜ☆電王戦IIに出た棋士もコンピューターもみんな好きだぜ☆▲(パソコン将棋)WCSC29一次予選36位、SDT5予選42位▲(パソコン囲碁)AI竜星戦予選16位

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント