Ken Okabe氏による
- 関数型プログラミングが『銀の弾丸』であるという非常識な常識2022 https://kentutorialbook.github.io/functionalprogramming2022/
の率直な感想を書いていきます。
「【追記】」の部分はTwitterでの他の人の反応や氏のはてなブログによる反論を受けて記載したものです。
JavaScriptで演算子オーバーロードを実現しようとするのは筋が悪い
氏は二項演算子に拘っておられますが、JavaScriptにはユーザー定義可能な演算子オーバーロードはないのだから、JavaScriptに適したやり方(関数・メソッド)を使うか、演算子オーバーロードに適した言語(特にStandard ML, OCaml, Haskellなどはユーザー定義の演算子を書けます)を使うべきだと思います。
【追記】もちろんC++やRustでも演算子オーバーロードはできますが、C++やRustを含む多くの言語では演算子としてあらかじめ決まった種類のものしか使えません。「パイプライン演算子がないから |>
を演算子として使おう」ということはできないのです。一方で、上の段落で挙げたML系言語では(言語が許す種類の文字からなる)任意の記号列を演算子として定義することができます。元の文書の主題からすると任意の記号列を演算子として使える方が好ましいかと考えたのでStandard ML, OCaml, Haskellを挙げました。
例として、氏の「パイプライン演算子」を見てみましょう。氏のパイプライン演算子は
// f(x) に相当するコード
P(x)['>'](f)
という形をしています。まず、文字数が増えています。また、18.8にある定義を見ると、元の値がObjectであればそれ自身を改変するコードとなっています。例えば、氏のパイプライン演算子を使うと次のコード
const x = {'>': "Hello world!"};
console.log(x['>']);
P(x)['>'](x => x);
console.log(x['>']);
は
Hello world!
[Function: value]
を出力します。与えられた引数を改変しており、これは汎用ライブラリーとしては非常に行儀の悪い挙動です。
氏がそこまでJavaScriptにこだわる理由は私には分かりませんが、「アテにならない」TC39が支配するJavaScriptに無理やり二項演算子を定義するのではなくてもっと筋の良い言語の啓蒙に勤しむ方が活動として有意義だと私は考えます。
【追記】このセクションは特に私の「感想」色が強く、人によって意見が異なることは自然なことだと思います。なので、あまりとやかく言い争う気はありません。
reduceにはinitialValueを指定しよう/reduceは二項演算と言えるか?
JavaScriptのArray.prototype.reduceは次のような引数を受け取ります:
array.reduce(callbackFn, initialValue)
ここで、initialValueは省略可能です。MDNの説明を見てみましょう。
initialValue Optional
A value to which previousValue is initialized the first time the callback is called. If initialValue is specified, that also causes currentValue to be initialized to the first value in the array. If initialValue is not specified, previousValue is initialized to the first value in the array, and currentValue is initialized to the second value in the array.
Exceptions
TypeError
The array contains no elements and initialValue is not provided.
initialValueが省略されたときの挙動を見てください。initialValueが省略された場合は、配列が空でなければreduceは
callbackFn(... callbackFn(callbackFn(array[0], array[1]), array[2]), ..., array[array.length - 1])
を返します。そして、入力となる配列が空だった場合はTypeError例外を送出します。
言うまでもなく、TypeError例外が発生する状況はプログラマーとしては避けたいです。そして、この場合はinitialValueをきちんと与える、というのが簡潔な解決策になります。reduceに渡す演算がモノイド演算であれば単位元を与えれば良いでしょう。加算なら 0
, 乗算なら 1
です。
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].reduce(add, 0)
堅牢なプログラムを書く上では、reduceは二項演算ではなく三項演算として捉えるべきです。
【追記】initialValueを省略した場合に「加法の場合は0となる」「乗法の場合は1となる」という説明は間違っています。だって空配列に .reduce(add)
を適用しても 0 は返ってこないでしょう?氏の反論記事では空配列のことを無視しており、私の文章の書き方が悪かったかなあと反省しております。
ちなみに、堅牢なプログラミング言語であるStandard MLでは、JavaScriptのreduceに相当する関数 List.foldl
はきっかり3つの引数を受け取る関数となっています。
val foldl : ('a * 'b -> 'b) -> 'b -> 'a list -> 'b
「型=集合」か?
「型」が何かというのは(私にとっては)難しい問題です。
初学者向けには「型は集合のようなものだよ」という説明で良いかもしれません。
しかし、私が思うに、型は集合よりも幾分抽象化されています。ここでの抽象化というのは、できる操作が限られているという意味です。例えば、
- 集合は自由に和集合 (union) や共通部分(交差, intersection)を取れますが、型について和や交差を取れるかどうかは型システムに依存します。
- 例えば、今のTypeScriptにはunion typeやinteresction typeがありますが、リリース当初のTypeScriptにはどちらもありませんでした(union typeはTypeScript 1.4から、intersection typeは1.6からです)。
- 別の例で言うと、Haskellにはそもそも部分型関係がないためunionもintersectionもありません。
- 集合に対しては冪集合 (power set) という構成がありますが、型に対する類似物はあまり聞きません。ある型の部分型全てを集めた型…となるのでしょうか?
- 【追記】「
A -> Bool
がそうではないか」という意見を頂きました。特性関数と部分型を同一視すればそうなりそうですが、筆者としては「部分型を集めた」感がないなあ、と思ったのでこの記事の当初の版では言及しませんでした。
- 【追記】「
という点で型と集合は違うものだと考えます。
繰り返しますが、私は初学者向けに「型は集合のようなものだよ」と説明することを否定はしません。しかし、Twitterで「こいつ @mod_poppo は、型が集合である事実すらしあず」と仰っているからにはKen Okabe氏は本気で「型=集合」と考えているようです。それほどご自身の信念に自信をお持ちなら、解説文書中の「型」を全部「集合」に置き換えてはいかがでしょうか。
FunctorとMonadは二項演算か?
HaskellのFunctorやMonadはそれぞれ
(<$>) :: Functor f => (a -> b) -> f a -> f b
(>>=) :: Monad m => m a -> (a -> m b) -> m b
という二項演算を持ちます。Monadはこのほかに単位射 return :: a -> m a
を持ちます。Monadについてはこの時点で「二項演算」だけじゃないだろって感じですが。
ここで、一般的な圏論の教科書における関手 (functor) の定義を確認してみましょう。ここでは最近出た「みんなの圏論 演習中心アプローチ」を当たってみます。5.1.2節によると、関手の構成要素は対象関数および
対象のすべての対 に対する射関数 (morphism function)
だそうです。
ここで、もしもHomが(プログラミング言語における)関数型のようなものであればこれはカリー化された関数、二項演算と思えるでしょう。しかし、 の は集合の間の関数の意味なのに対し、行き先の は圏 の射です。( でない限り)住んでいる世界が違うのです。なので、圏について特別の事情がない限り、関手は二項演算とは言えないと考えます。集合と写像の圏 やHaskellの型と関数の圏(っぽいもの)には特別の事情(内部ホムの存在)があるため、関手が二項演算だと思えるわけです。
モナドについては、「圏論の基礎」を当たってみましょう。第VI章「モナドと代数」の最初の定義がモナドで、曰く
定義1 圏 におけるモナド (monad) は函手 と二つの自然変換
からなり,次の図式を可換にするものである.
(図式省略)
だそうです。この本の中では は単位元 (unit), は乗法 (multiplication) と呼ばれていますが、私の記憶では は単位射と呼ばれることもあったと思います。
「圏論の基礎」での はHaskellのMonadに対応させるなら return :: a -> m a
で、 は join :: m (m a) -> m a
に相当します。モナドの数学的な定義にはHaskellの >>=
に相当するものは含まれていないのです。なので、モナドのことを二項演算と呼ぶのは不適切だと考えます。
これもやはり圏についての特別の事情があれば話は別で、strong monadと呼ばれる構造を持つモナドであればお馴染みの (>>=) :: m a -> (a -> m b) -> m b
に相当するものが定義できます。
【追記】私は「型≠集合」という立場なので関数型プログラミングのモナドが集合圏上のモナドと同じものだとは思いません。
「タイプコンストラクタ」の用法
詳しい人向けの解説:氏の文書では「タイプコンストラクタ」を「(モナド等の)単位射」の意味で使っています。これは間違いです。
19.6より引用:
こういう何もないところから、ある特別な型(Type)を新規に構築する(生み出す)関数のことを、
型構築子/タイプコンストラクタ(Type constructor)といいます。
オブジェクト指向でいうところの、コンストラクタ(Constructor)に該当します。TypeScriptにおいてはタイプコンストラクタにも当然きちんと型(Type)がつくのですが、
ジェネリックを使って、以下のようにタイプ定義します。type F<A> = A[]; const F = // type constructor <A>(a: A): F<A> => [a];
素の値であるAから、
タイプコンストラクタであるFによってF<A>
という新しい型(Type)が新規に構築された(生み出された)様相がう> まく表現されています。
とのことです。ここで定義した F
は (a => [a]) : <A>(a: A) => Array<A>
という関数で、要素が1つの配列を作る関数です。Haskell風に型を書けば a -> F a
となるでしょう。これはモナドの単位射に他なりません。
一方で、型構築子 (type constructor) の世間一般での意味を確認しましょう。
まずは「型システム入門 プログラミング言語と型の理論」を見てみます。定義9.1.1では、「型構築子 」とあります。ここでの型構築子は関数型を表記する のことのようです。そして11.12には
これまで見てきた型付けの機能は、BoolやUnitといった基本型もしくは、既にある型から新たな型を作る や といった型構築子に分類できる。別の便利な型構築子としてはListがある。
とあります。説明の通りですが、すでにある型から新たな型を作るものが型構築子です。TypeScriptで言えば関数型 =>
や配列型 Array<>
が該当します。
type constructorについては、Wikipediaにも記事があります。ここでは、基本型のことも(0項)型構築子と呼んでいます。
いずれにせよ、型構築子というのは型を作るもので、型レベルの概念です。「その型の値を作る値レベルの関数」ではありません。オブジェクト指向の「コンストラクタ」と混同しないでください。
用語に関してついでに言うと、Ken Okabe氏の文書ではMonadを返す関数のことを「Monad関数」と呼んでいるようです。Haskellで言えば a -> m b
みたいなやつです。圏論の文脈的には、これにはKleisli射という名前がついています。
Ken Okabe氏の22.9には
基本的に、プログラミングを含む工学では、なるだけ既存の数学的な概念と用語を踏襲すべきであって、同じ意味の造語を無闇に増やすことはあまり意味がないどころか、混乱をもたらすだけだと考えます。
という記述があります。私としてはこの記述に非常に同意します。Ken Okabe氏自身がこれを徹底していればもっと良かったと思います。
最後に、Ken Okabe氏へ
この記事について反論があるなら元の記事に追記するか、ご自身で新たに記事を書いてください。
読者にとって重要なのはTwitterでのバトルの勝者ではなく、それぞれが書いた記事のどちらに説得力を感じるか、でしょう。なのでTwitterでの見苦しいバトルは不毛です。
というわけで、Twitterで私にこれ以上絡むのはやめてください。私もあなたの相手をする時間が無制限にあるわけではないので、これ以上粘着されるようであればブロックします。言いたいことがあるなら記事に書いて、読者の判断に委ねると良いでしょう。
コメント
@stken2050(編集済み) リンクをコピー このコメントを報告 本書いたら数学愛好者の中級レベルのプログラマーからマウンティングを試みられた話 - stq2050’s blog https://ken-okabe.hatenablog.com
0
@stken2050(編集済み) リンクをコピー このコメントを報告 【モナド編】本書いたら数学愛好者の中級レベルのプログラマーからマウンティングを試みられた話 - stq2050’s blog https://ken-okabe.hatenablog.com
0
@stken2050(編集済み) リンクをコピー このコメントを報告 【追記への反論編】本書いたら数学愛好者の中級レベルのプログラマーからマウンティングを試みられた話 - stq2050’s blog https://ken-okabe.hatenablog.com
0
@stken2050(編集済み) リンクをコピー このコメントを報告 【+α+タイプコンストラクタ編】本書いたら数学愛好者の中級レベルのプログラマーからマウンティングを試みられた話 - stq2050’s bl... https://ken-okabe.hatenablog.com
1
@Zuishinリンクをコピー このコメントを報告 3
@stken2050(編集済み) リンクをコピー このコメントを報告 0
@stken2050(編集済み) リンクをコピー このコメントを報告 関数型プログラミングが『銀の弾丸』であるという非常識な常識2022 https://kentutorialbook.github.io
0
@Zuishinリンクをコピー このコメントを報告 0
@stken2050(編集済み) リンクをコピー このコメントを報告
0
@Zuishinリンクをコピー このコメントを報告 0
@stken2050リンクをコピー このコメントを報告 0
@Zuishinリンクをコピー このコメントを報告 0
@stken2050リンクをコピー このコメントを報告 0
@Zuishinリンクをコピー このコメントを報告 0
@stken2050リンクをコピー このコメントを報告 0
@Zuishin(編集済み) リンクをコピー このコメントを報告 0
@stken2050リンクをコピー このコメントを報告 0
@Q-Saburouリンクをコピー このコメントを報告 0
@Q-Saburouリンクをコピー このコメントを報告 0
@Q-Saburou(編集済み) リンクをコピー このコメントを報告 1
@Q-Saburouリンクをコピー このコメントを報告 0
@Q-Saburou(編集済み) リンクをコピー このコメントを報告 0
@stken2050リンクをコピー このコメントを報告 型はオブジェクト(対象)であり集合の圏なら集合 カリー=ハワード=ランベック(同型)対応 - stq2050’s blog https://ken-okabe.hatenablog.com
0
@stken2050リンクをコピー このコメントを報告 JavaScriptには関数の末尾再帰最適化がないので関数型には不向きだというデマ - stq2050’s blog https://ken-okabe.hatenablog.com
1
@stken2050リンクをコピー このコメントを報告 Quoraでの「関数型プログラミングが『銀の弾丸』であるという非常識な常識 2022」の書評 - stq2050’s blog https://ken-okabe.hatenablog.com
0
@stken2050リンクをコピー このコメントを報告 「参照透過性」という用語は裸の王様と言えない愚者のための概念 - stq2050’s blog https://ken-okabe.hatenablog.com
0
@Q-Saburouリンクをコピー このコメントを報告 0
@Zuishinリンクをコピー このコメントを報告 0
@stken2050(編集済み) リンクをコピー このコメントを報告 
0
本書いたら数学愛好者の中級レベルのプログラマーからマウンティングを試みられた話
中編です。遅くなりました。
【モナド編】本書いたら数学愛好者の中級レベルのプログラマーからマウンティングを試みられた話
【追記への反論編】本書いたら数学愛好者の中級レベルのプログラマーからマウンティングを試みられた話
【+α+タイプコンストラクタ編】本書いたら数学愛好者の中級レベルのプログラマーからマウンティングを試みられた話
ていうか、あれを全部読んだんですか?
10 回のループの代わりに 1 から 10 までの配列を手書きで用意しているのを見た時点で目を覆いましたが。
@Zuishin それは後で、ちゃんと続く章で別の関数に置き換える解説をしているんですね。
目を覆うのは勝手だけど、読まないで誹謗中傷するのはやめてもらえます?この記事の書き手もまともに読まずにネガキャンしているけど。
New!【ReactのためのFRP(ReactiveMonad)のDemo その他】の章を最後に追加しました
関数型プログラミングが『銀の弾丸』であるという非常識な常識2022 Demo
後で書き換えたらいいという話ではなくて、「あらかじめ 1 を 10 回足す計算をしておいたのでコンピューターが足さなくて済むようになりました」という論旨に目を覆ったという意味です。100 でやってみたら for の方が短くなることがわかるんじゃないですかね。
「あらかじめ 1 を 10 回足す計算をしておいたのでコンピューターが足さなくて済むようになりました」なんて論旨は存在しないですけどね。
と概念的に等価だけど、このコードを解説するためには、まずその土台として、
[1,2,3,4,5,6,7,8,9,10]
と素朴に始める必要がある。つまり「後で書き換えたらいいという話ではなくて」じゃなくて、後で書き換えるように解説を運ぶ必要がある。
10000でやってみても、こちらのコードのほうが短く簡潔になりますけど?
また「短くなる」なんてものは本旨でもなんでもない、コードの簡潔さの話をしている。
読んでもおらず論旨の運びも知らないのに「論旨に目を覆ったという意味です」もなんもないでしょ。あなたは論旨なんてものを理解もしていないのだから。
だめだこりゃ。何を言われてるのか全く分かってない。
「何を言われてるのか全くわからない」「意味不明」だと思うのは僕に限らないと思うけどね。
まともに言語化できるものならやってみたら?
言語化はしてるので、読めるなら読んでくださいとしか。
読めないのは私のせいではないので、読める人に聞いてください。
すでにチャットで3名にあなたのコメント見せて、聞いてみたけど、全員、意味不明だということで合意できています。
それは残念ですね。
僕もそう思います。まっとうに言語化できないのは自由だが、人の著作を批判する際には、その残念さは悪質になる。
きちんと論旨を理解した上で、何がどうなのか人に説明もできないままにネガキャンやってるわけでしょ?
その範囲ですら読んでもないのに。
言語化はしているので、読める人に聞いてください。
読めないのは私のせいではないので。
あなたの残念な付き合いも私のせいではありません。
僕の知り合いには、あなたの表現をあなたがなんか思ってるそのままに読解できる知り合いは現状居ないし、探しても居ないと思うので、あなたの知友の範囲で用意してみたら?
自分でうまく表現できないのなら、お友達に代弁してもらったら?
新潟の岡崎と申します。落ち着きましょう。他人様のコメント欄でこのような軽口の応酬のような喧嘩をするべきではありません。あたしは乱暴な人がきらいです!
岡部さんはUCLAを卒業されたと以前表明されていました。ですので、言っていることは正しいのかもしれませんね。
岡部さん!スパムの投稿はよくありません!ここがどこなのか、よく考えて!
あたし、乱暴な人きらい!UCLAの名前が、泣いていますよ!不服なら、長澤弁護士に頼りましょう
誹謗中傷はやめるべきです。あたしは岡崎という者。
自分のブログで書けないからって、捨てアカでこんなところで突然誰かの名前を晒すなんて卑怯ですよ。アンフェア。反省して。
mod_poppoさん、お騒がせしました。代わってお詫びします。あたしも去ります
いくら5年前にQIITAで@kenokabeアカウントを永久凍結されたからといって、こんなことをするんですね。恥ずかしい人です。あんなの自業自得じゃないですか
岡部さん(@stken2050)、コメントを削除して再度同じ文章を投稿するのはマナー違反です。
ご自分の発言に責任を持ってください。何か自分の投稿が一番下に来るようにしたい事情でもあるのでしょうか。UCLA卒業したのでしょう?あれは嘘だったのでしょうか?そうでないなら、UCLA卒業の矜持を見せてください。
@stken2050 さん、また投稿を消して新規投稿をしてますね!呆れた人です。
そして、あたしはそのちくわという人ではありませんので、その人とのことは勝手になさってください。あたしに断りを入れる必要もありません。
あたしには何をされても痛くもかゆくもありません。ご自由に。
兵庫県警とか、あるいは長澤弁護士からの内容証明ですね?わかります。へでもありません
あたしの言論はあたしだけのもの。今後も末永く誹謗中傷を批判していきます!
記事主さん、ご迷惑をおかけしました。
型はオブジェクト(対象)であり集合の圏なら集合 カリー=ハワード=ランベック(同型)対応
JavaScriptには関数の末尾再帰最適化がないので関数型には不向きだというデマ
Quoraでの「関数型プログラミングが『銀の弾丸』であるという非常識な常識 2022」の書評
「参照透過性」という用語は裸の王様と言えない愚者のための概念
トピ主様、お騒がせしました。stken2050さん、スパム投稿は控える事を進言いたします
@Qiita
スパム広告多いので削除しといてください。
そんなマナーなどない。ソースは?
おまえ=ちくわ のコメントは明らかに急遽こしらえた捨てアカウントによるオフトピックの荒らしコメント連投のスパムだが、こちらはすべて本書への批判の内容に呼応した記事のリンクであり、おまえの迷惑なスパムコメントへの通告については連投にならないように留意している。
本件のおまえの行動については前回刑事告訴した所轄警察署へ芦田真一が再度同様の犯行を行っていると通報した。これは断固とした強い警告なのだが、今後の動きを見守りながら再度刑事告訴する。スクショもすべて保存している。すでに前回のことがあるので今回は容易だろう。身元も完全に割れてることだし。
同時にQiita運営には法的要件を満たす形で正式に通報した。まもなくそちらに法的プロトコルに則った通告が届くだろう。
@Q-Saburou
にアカウント変更
↑
$ analyze @Sacchii-aum
投稿した記事
No data
LGTMした記事
No data
回答した質問
No data
またスパム捨て垢を急遽こしらえて荒らしに来たんだ?
@Sacchii-aum は僕が刑事告訴した誹謗中傷犯

ちくわ 芦田真一
でQiitaにも捨てアカウントを継続的に作成しながら
5chの粘着スレでほぼ毎日のように書き込み、同じように別人格も装いながら、
10年間ネットストーキングしている。
末尾の-aumというのは5chでなんか頭のおかしいこと言ってる「オウム真理教」キャラの示唆。
これでチクワとはっきりわかる。
https://twitter.com/tikuwa_zero
上のアカウントデータでも明白なとおり、極めて特異な挙動を示しており、本件専用にコメント欄を荒らす目的でQiita上に急遽作成した捨て垢。しょせんこれがQiitaの炎上の正体。
だいたいQiitaではネカマで出てくる。