<前回の記事>
「 中級者向けに書くぜ☆ 初心者はふるい落として、基本的な説明を省いて 用語をどんどん使っていくぜ☆」
「 コンピューターが勝手に カリー化 してくれるんだから、人類は黙って 多変数関数 使ってればよくない?」
2 + 3
3 + 2
x + y
「 ↑変数 x、 y はどこかのタイミングで決まるとしよう☆ これを Function で書いてみよう☆」
add( x, y )
{
x + y
}
「 ↑これは 足し算記号に add という名前を付けただけの、あんまり嬉しさもない簡単なやつだぜ☆」
= add( 2, 3 )
= 5
「 引数が複数ある、または、返り値が複数ある 、そんな Function を、
引数が1つ、かつ、返り値は関数が1つ な Higher-order function に変えるのがカリー化だぜ☆」
「 引数が複数ある Function が どうやって 引数1つになるんだぜ☆?」
「 ↑Functionに 変数を覚えさせておけるようにして、
その Function を、さらに別の Function の中で呼び出せばいいわけだぜ☆」
apple( x )
{
banana( y )
{
x + y
}
}
「 ↑カリー化すると apple は高階関数、 banana は一階関数になる☆
そして banana から見れば 変数x は 自由変数、 変数y は 束縛変数 に見えるぜ☆
しかし apple から見れば 変数x も y もともに束縛変数に見ることが お分かりいただけると思う☆」
= apple( 2 )
= banana # ただしxは2になっている。
「 apple は banana を返すことは お分かりいただけるであろうか?」
「 この banana は一階関数として使えるんじゃないか☆?」
= banana(3)
= 5
= apple( 2 )( 3 )
= banana( 3 )
= 5
= add( 2, 3 )
= 5
「 ↑これは カリー化されていない Function で……☆、」
= apple( 2 )( 3 )
= 5
「 カリー化 の操作方法は調べれば出てくるけど、 なぜカリー化を使いたいのか は調べても ヘタクソな説明 だけ出てくるのよ」
「 なにが嬉しくて カリー化したFunction を作んの?」
「 ↑ 入れ子 が作りやすくなる ☆
上図は どんなに入れ子しても 引数は 一番内側の Function に渡される1個だぜ☆
一番シンプルな入れ子の例だが、 ここで注意してほしいんだが☆、」
「 入り口が1つでも 中で複数個に分かれている ということはある ☆」
「 図にすると 分けわからんが、式を書く人類にしてみれば……☆」
「 シンプルな入れ子にする手間だけで その分け分からん構造を 作れるんだぜ☆」
「 自由変数がなく、計算が独立している かたまりを 小分け にしながら 振り分けることができる☆
自由変数がなく、計算が独立していると 何に効くかというと、絵に描いて説明してみよう☆」
「 apple( x )( y )
みたいなやつは 自由変数を持っていないので コアに丸投げできるな☆」
「 apple( x )( y )
は banana( y )
みたいに小分けにして さらに振り分けることができる☆
どう小分けにするかは もっと低層の、機械寄りの、プログラム にやらせればいいだろう☆
add( x, y )
は 小分けにできない☆」
= apple( 2 )( 3 )( 4 )
= banana( 3 )( 4 )
= cherry( 4 )
= 9
「 クロージャーの中に 変数が隠れてしまって 筆算の役には立たないわよ」
「 それを Abstraction (アブストラクション;ラムダ抽象) と言う☆
計算は コンピューターがやるんで、人類は 式を間違わずに書くことだけ 集中しろだぜ☆」
「 下の計算結果が 上に帰ってこないと、上は次に進めないんだから、
下の処理を 別コアに ちぎって投げる意味なくない?」
「 これは 足し算 を例にしてるから うま味が 見えないんだぜ☆」
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 )
「 もしかすると banana は ちぎって配れるやつかもしれない☆」
「 Java Script は シングル・スレッドのくせに NodeJSエンジン の forループ文、
ログの内容が順番バラバラに書かれている気がするんだが どうなってるんだぜ☆?」
「 返り値は1つしかないのに、どうやって 小分けにしてんの?」
「 疑似コードで言うと、 Async、Async、Async、Async、Await all
とかだな☆
Rust 言語には 2019年10月時点で Async/Await 構文が無いんで この話に入っていけない☆ どうしようもない☆」
「 せっかく非同期処理なのに await で いちいち同期を取るのが 意味分かんないぜ☆」
「 複数の非同期コードを 配列かどこかに詰めて 一括して await できるやつが どっかにあるだろ☆」
「 で、ほとんどのプログラム言語は カリー化 とか 人類が考えなくても
コンピューターが勝手に カリー化 に翻訳して実行してくれるだろ☆
気にせず add( x, y )
の形の Function を使えだぜ☆」
「 関数コールは遅い☆
カリー化の真似して 見た目だけ合わせて書いたところで 無理くり合わせているだけで 実行速度が遅くなるだけかもしらん☆」
<次の記事>
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント