講演をきいたことがある。fish.(拙訳)誰が水を発見したかは知らないが、発見者が魚でなかったことは確かだ。誰しも信念という水の中を泳ぐ魚のような存在だ。思い切って飛び跳ね空気に触れてみなれば、自分が信念という水の中にいることに気付かない。ある手法の利点を語るには、その手法の欠点や、他の手法の利点や欠点とできるだけ客観的に比較しなければ説得力がない。これを実践するのは難しい。この記事では、客観的になれているか自問自答しながら、動的型付き言語と静的型付き言語について比較してみようと思う。静的型付き言語から動的型付き言語に移った人の気持ちも分かるつもりだし、その逆も分かるつもりだ。(いや、分からないことも多いんだろうけど。)一口に動的型付き言語、静的型付き言語といっても実にさまざまで、本当は十把一絡げに議論することはできない。細部にこだわると言いたいことが伝わらなくなると思うので、細かい点には目をつぶって頂けると嬉しい。以下では僕の立場上、動的型付き言語のプログラマが主張する動的型付き言語の利点や静的型付き言語の欠点が、静的型付き「関数型」言語のプログラマからどういう風に見えるのかという話になる。すべての動的型付き言語のプログラマがそういう主張をしているとは思っていないし、静的型付き関数型言語を一括りにするのも乱暴なのは承知している。「なんか違うな」と感じたら、建設的なブログ記事をなどを書いて議論して頂けるとありがたい。静的型付き言語であってもコンパイルして実行するというラッパープログラムを書けば、スクリプトのように実行できる。実際、静的型付き関数型言語では、そいうラッパープログラムを提供しているものが多いし、よく使われている。き言語では型注釈を書かなくてもいいので記述量が減って楽だ」うまく設計された静的型付き言語では、型注釈と定義が分離されている。cだから、型注釈は省略して書ける。c静的型付き関数型言語の多くは、型推論という機能を持ち、定義から型を推測する。そこで必要であればコンパイラが推論した型をプログラミング環境が自動的に挿入してくれる。対話環境があれば開発効率がよいという主張には完全に同意。静的型付き関数型言語の多くにも対話環境がある。個人的な意見では、対話環境がある言語でもリテラルが充実してないのであれば、対話環境の利点が半減していると思う。定義されたデータは、それがそのままリテラルとなり、関数の入力にも使えるし、出力の際もそのままの形で表示される。3)入力も出力も定義がそのままリテラルになっていることが分かるだろう。テスト「動的型付き言語はテストしやすい」これは意味が分からなかったのだが、たとえば「呼び出すメソッドを実行時に決定する機能を使ってモックを差し込むことがやりやすい」ことなど言っているのではないかと教えて頂いた。たしかに静的型付き言語のオブジェクトをテストするのに比べれば、動的型付き言語のオブジェクトをテストする方がやりやすいだろう。それはオブジェクト指向で考えているからではないか(十把一絡げにしてすいません)?関数プログラミングの場合は、差し替えたい部分があるなら、そこは引数にしておく。テストのために「実行時に呼び出すメソッドを変えたい」とは思わない。引数を変えればいいからだ。話がそれるけれど、関数型言語では副作用のある関数とない関数を分けて書く習慣を身につけているプログラマが多い。副作用のない関数は、引数だけから結果が決まるのでテストしやすい。副作用のある関数でも、上記のように動作を変えたい部分は、引数にしてテストしやすいように工夫する。世の中のコードはうまく設計されているものばかりじゃない。うまく設計されてないコードを手渡されたときに、実行時に呼び出すメソッドが変えられるのでテストしやすい。いう意見には一理あると思うけど、僕だと(変更が許されるなら)リファクタリングしてテストしやすく変更すると思う。その方が保守しやすくなるからね。ちなみに、副作用のない関数に関しては、テストケースを自動的に生成するというテスト手法があって、静的型付き関数型言語ではよく使われている。この種のテストでは、関数が持つべき「性質」を記述する。tests.100個の乱数が生成されて、すべてテストを通過したことが分かる。値の生成方法にも、乱数的に生成する方法の他に、ある大きさを網羅する方法などがある。テストの世界は広くて深い。ある局面で「テストしやすい」と言われても「あなたの場合だとそうなんでしょうね」という感想になることが多い。スキーマを取ってきて、必要なメソッドをメタプログラミングで自動生成することなどを言っている。スキーマを取ってきて必要な関数/メソッドを自動生成できる。き言語は不完全なコードを実行できる」おそらく動的型付き言語の利点は、この言葉に集約されると思う。これはかなり大雑把な表現なので、もう少し厳密に議論したい。静的型付き言語でも不完全なコードは実行できる。{}何も実装してないから(仕様を満たさないという意味で)不完全だけど、コンパイルもできるし、実行もできる。コードを最初の方で示した。いう訳で、言いたいことは分かるんだけれど、もう少し的確な表現を使う方がいいと思う。以下では、このテーマを細分化して議論していく。「少ない手間」とは、ある部分であるメソッドを呼び出しているのに、そのメソッドの定義は一文字も書かれていないなどを言っている。静的型付き言語では、定義されてないメソッドや関数があれば、プログラミング環境が関数定義の雛形を自動挿入できるので、動的型付き言語の利点とは言えないと思う。「動的型付き関数型言語では、公開しているインターフェイスの互換性を保ちながら、新しい仕様に変更できる」たとえば、第一引数が整数で第二引数が文字列である関数を公開しているとしよう。利用して行く過程で、順番は逆の方がいいと気付いた。動的型付き言語であれば、実行時に第一引数の型を検査し、整数なら古い仕様で、文字列なら新しい仕様で動くということが可能だ。自分が提供するライブラリの顧客が、顧客側のコードの変更を認めてくれないのであれば、こういう対策が必要になる。いった状況では、動的型付き言語の方が有利。静的型付き言語のプログラマは、このような変更がなされたら、速やかに新しいインターフェイスに移行するべきだと考えている。コンパイラは、変更すべき箇所をすべて見つけてくれるので、顧客が変更を認めてくれないという状況でない限り、変更は可能だし、変更の手間もかからない(ただ必要な人への連絡は手間だ)。これは一長一短である。静的型付き言語のプログラマにとっては、変更すべき箇所を指摘するツールがないのは不安に感じるだろう。(静的解析ツールを提供している動的型付き言語もあるが、言語処理系に組み込まれていないと、言語処理系の変化に取り残されてることがよくある。)動的型付き言語のプログラマにとっては、変更に対する柔軟性がないのは不安に感じるだろう。これらの言語は、たとえコードが不完全でも動き続けなければいけない。あるシステムを制御するユーザインターフェイス言語の設計者は、自然と動的型付き言語を選択するだろう。動的型付き言語は品質の面に不安があるので、コード生成を利用しているプログラマもいる。生成するという方法が一部で流行っている。ブラウザを制御するためのアセンブリ言語である。動き続けなければならないサーバのコードの一部をバージョンアップしたい。書かれたサーバでは、コードのホットスワップが当たり前のように実践されている。静的型付き言語でもやってやれないことはないと思うけど、動的型付き言語の方が圧倒的にやりやすいのは間違いない。デバッガでのプログラミング「動的型付き言語では、変わりゆく世界を動的に捕まえてプログラミングできる」コードを書いたときには想定してなかったか、気付いてはいたがどう対処すればよいのか分からずにそのままにしていた箇所があるとしよう。優れた動的型付き言語では、そこを踏むとデバッガが起動する。デバッガの中で対処するコードを書いて再実行すれば、あたかも前からコードがあったかのように動いてくれる。優れた動的型付き言語の優れたプログラマは、もう再現できないかもしれない千載一遇のチャンスを無駄にしたくない。このようなプログラマにとっては、デバッガなどのプログラミング環境がプログラミング言語だ。このようなプログラミングを実践しているプログラマは、本当に尊敬する。残念ながら、静的型付き言語では、このようなプログラミングはできないか、相当無理がある。まとめ僕の考える動的型付き言語の利点をまとめると以下のようになる。おまけ動的型付き言語のプログラマが知らないかもしれない世界として、静的型付き関数型言語では「型が実装を導いてくれる」ということが挙げられる。知らないのであれば、実際に体験してみると静的型付き言語に対しての印象も変わるかもしれない。さんのブログを呼んで頂けると、詳しく分かると思います。記述量Haskellで型注釈を省略して書けるのは良いのですが、基本推奨されないように思います。それよりも大規模なJSやRubyのアプリケーションなら、JSDocやRDocを書くから型を書くのと変わらないという方が個人的には正しいと思っています。テスト関数型で言及されているテストは純粋な関数に対して言及されてることがほとんどで、データを永続化するような副作用のある関数に対して本当に簡単に書けるのか気になってます。Railsを利用していますが、正直、型のある言語が使いたいです。コードには、トップレベルの型注釈を付けることが推奨されています。どのようにコードを書くかに特にルールがある訳ではありません。関数型の副作用のある関数のテストが、他のパラダイムと比べて、テストを書きやすということはないと思います。テストケースを書いて行きます。発見したというすごい事例もあるんですが、僕はまねできません。テストできる可能性がでていました。多くがやっている状況ではありません。オーバーロードなどで対応できるのは知っています。この記事では、僕の静的型付き言語からくる偏見をなるべく排除するために、動的型付き言語の利点はなるべく認めて、静的型付き言語の利点はなるべく認めない方向で書いています。できなければ認めていません。できるという話も聞きますが、この辺りはよく理解していません。方が記事を書いてくれることを期待しています。アスペクト指向の研究が2つぐらいありますが、実用化されてはいません。静的に型付けできない、あるいは難しい型理論の世話にならざるをえないのは一体どういう場合なのかを問題にすべきです記事を書いて下さい。10:16考えがまとまらないので羅列になってすみません・Javaのようにダウンキャストがないと使い物にならない言語は静的言語とは呼びたくない・適切な型を考えるのは難しいしさぼりたい。型理論をちゃんと理解していないとコンパイルエラーメッセージが理解できない。ランクN多相とか依存型とか...・Phantom型は動的型言語では実行時エラーにするにしてもうまくいかないのではないか・Erlangのホットスワップを可能にしているは、データに型情報などがついているからではないか。変数の片付けとはさしあたって独立しているような気がする。10:24型理論を理解しなくても静的型付き関数型言語の型システムは使えます。エラーメッセージで警告される場所が、実際に問題がある場所とかけ離れていたりして、難しいことはあります。この辺りは、研究課題のようです。データに型情報が付いているのは、多くの動的型付き言語に見られる一般的な特徴ですね。10:25ランクN多相、依存型、Phantom型は、僕はあんまり理解していませんし、使いもしません。(人の書いたコードを読まないといけないことはありますが。02:14今さらという感じがするのですが、テストの段落について感じたことをコメントさせて下さい。山本さんの書かれている「関数プログラミングの場合は、差し替えたい部分があるなら、そこは引数にしておく。」は、関数プログラミングの考え方でもありますがオブジェクト指向プログラミングの考え方でもあると思いました。クラスベースのオブジェクト指向だと、差し変えたい部分を新しいクラスとして定義しそれを使うクラスのコンストラクタやメソッドの引数にするからです。「「実行時に呼び出すメソッドを変えたい」とは思わない。引数を変えればいいからだ。」も同じことを言っているように感じました。オブジェクト指向において、コンストラクタやメソッドの引数を変えることは実行時に呼び出すメソッドを変えることにつながるからです。00:45動的型付け言語の生き残る理由は、殆どの静的型付け言語の型システムがチューリング不完全だからだと私は考えます。静的型付け言語の評価項目の一つに、その言語の持つ型システムがあります。型システムが強力であるほど、その言語は便利となります。ある静的型付け言語では型に応じて手動展開しないと型チェックの通らないコードが、ランクN多相を導入した静的型付け言語では手動展開を省けたりします。「究極の型システム」が存在するならその型システムは、任意の性質Fを満たすかどうかもチェックできるでしょう。Wikipediahttp://ja.wikipedia.org/wiki/%E3%83%A9%E3%82%A4%E3%82%B9%E3%81%AE%E5%AE%9A%E7%90%86そのものであり、「究極の型システム」の型チェッカが相手ならば、無限ループやメモリ食いつぶしに陥らせるコードを書くことが可能です。これによるコンパイラのクラッシュor応答不能を防ぐため、ほぼ全ての静的型付け言語は、「究極の型システム」の装備を諦め、どこかで型チェックをサボります。この「型チェックのサボリ」の犠牲となったコードの扱いが、動的型付けと静的型付けで異なります。静的型付け言語の売りは、漏れなき型チェックなのですから、サボったコードは問答無用で型エラー扱いとなります。初期の静的型付け言語はランク2多相のコードを型エラーにするし、ランクN多相の言語はランクN+1のコードを型エラーにします。結果プログラマは、ランクN+1多相の様な高度なチェック技法を身につけていても、その言語のサポートする型システムの範囲内のコードしか書けません。これに対し動的型付け言語は、コンパイル時にチェックを諦めざるを得なかったコードでも実行を許します。ランク1多相しかチェックできない動的型付け言語でもランク2多相のコードを動かせるし、そもそも大抵の動的型付け言語は、コンパイル時に何もチェックしないというかコンパイルしなくても、任意の型システムのコードを動かすことが出来ます。プログラマは自分の使う型システムを、言語に制限されずに済むのです。コンパイラによるチェックがないならば、型システムの魅力は殆ど失われます。コンパイラの型チェックを行なうのに静的型付け「言語」である必要はありません。多くの静的型付け言語で採用されている「型推論」の技術は、型アノテーションを持てない動的型付け言語にも応用できます。チェックサボリについては「型エラー」ではなく「型警告」としてプログラマに通知すれば、プログラマ自身がチェックしなければならない範囲を大きく絞り込むことが出来ます。C言語コンパイラgccの「-Werror」オプションの様に、型警告を型エラーとして扱えば、同じコードが動的型付け言語ではなく静的型付け言語に化けます。「型推論」と、チェックサボリ=「型警告」のない「究極の型システム」とを組み合わせれば、静的型付け言語と動的型付け言語の間に、違いは残りません。裏を返せば、静的型付け言語と動的型付け言語の本質的な相違は、型チェックの不完全性に対する対応に集約されます。型システムのヘボが原因のものまでプログラマのエラーと同じ扱いにするのは、動的型付けに対する静的型付けの修正不能な短所です。現在のところ、静的型付け言語並みのコンパイル時チェックを持つ動的型付け言語を私は知りません。その登場は時間の問題だと私は信じます。その時が来たら静的型付け言語は存在意義を失うでしょう。記述ではなくて、具体的にたとえばPHPのサンプルコード(掲示板とかカートとか具体的なサンプルアプリ)を例示しておいて、ここがこうだから動的言語の場合はこうで静的言語であればこうである、関数型ならこうしたら利点がある、というような比較をしないと理解しづらいです。22:19pythonのmypyには頑張ってもらいたいものですねスパム対策のためのダミーです。例示のためのMACアドレス。