これは非常に広範で、あいまいで、おそらく哲学的な質問であることを知っています。ある程度、質問の中で最も重要なキーワード-「強力な」型システム-それ自体は ill-defined です。だから、私が何を意味するのか説明してみましょう。
質問の全体的なコンテキスト
Ruby on Rails)で非常に大規模なWebアプリを構築しており、スタックについては一般的に満足しています。必要に応じて、ものを本当に速く出荷することができます-"ビジネス"ケースの90%で機能し、約10%のエッジケースをあまり心配する必要はありません。一方、コードレビューとテストカバレッジの助けを借りて、ゆっくりと慎重に、すべての拠点をカバーするようにしてください。このような綿密な調査と安全に値する状況でのみです。
しかし、チームが成長するにつれて、スタックに組み込まれた「セーフティネット」が欠如していることに不快に感じ始めました。
私たちは最近、JavaでいくつかのネイティブAndroid=開発を開始しました。そして、コンパイルされた/静的/厳密に型指定された言語によって提供される安全性を(喜んで)思い出しました。
現在、これらの安全機能には長所がありますが、短所もよく知っています。さらに、「定型の重い」Javaの世界では。したがって、私はJavaの代わりに、人々が最近取り組んでいる現代の「強く型付けされた」多くの言語を調べ始めました。例:Scala、Rust、Haskellなど。最も興味深いのは、型システムと静的/コンパイル時チェックの能力です。
さて、質問
より大きなアプリケーションでこれらの強力な型システムと静的/コンパイル時機能を使用するにはどうすればよいですか?
たとえば、これらの強力な機能への標準の「hello world」のような導入をどのように進めればよいでしょうか?リッチタイプシステムを使用してビジネスドメインの問題をモデル化するものですか。タイプシステムは、30,000 LOC +ゾーンにいるときに役立ちますか、それとも妨げになりますか?システムが弱く型付けされた外部の世界とやり取りすると、これらの型システム(およびコンパイル時チェック)によって提供されるセーフティネットはどうなりますか。 JSONまたはXML API、さまざまなデータストア、ユーザー入力などを介して.
現時点では時間が足りないので、短い回答をさせていただきますが、現在2つの大きなプロジェクト(Haskellで100.000 LOCを超える)に取り組んでいます- flowbox.io および luna-lang.org 。私たちは、プログラミング言語のバックエンド、コンパイラー、さらにはwebGLベースのGUIを含むすべての部分にHaskellを使用しています。強力な型システムと「依存型」のような機構があなたを導き、他の言語で知られている負担と面倒からあなたを救うことができることを認めなければなりません。私たちは型を非常に広範囲に使用しており、コンパイル時にチェックできるすべてのものはそうされています。実際、過去3年間の開発中に、ランタイムエラーやスタックオーバーフローが発生することはありませんでした(これは本当に驚くべきことです)。唯一のエラーは、プログラマーが行った明らかな論理エラーです。多くの人は、Haskellでコンパイルされたものは機能するだけで、いつか顔に当たらないことを確信していると言っています。これはほとんどの状況に当てはまり、言語をよく理解していて、回避すべきことがわかっている場合(実装されていない型クラスメソッドなど)、型システムから安全に大きな利益を得ることができます。
質問の最初の部分への回答:次のようないくつかの優れたブログを読んで、これらの強力な型システム機能について学ぶことができます。
実際、他にもたくさんのニースブログがあります( planet Haskell など)。とにかく、高度な型システムを本当に理解するための最良の方法は、有用なオープンソースライブラリを開発することです。私たちは(FlowboxとNew Byte Orderで)多くのライブラリをリリースしています(Hackageで見つけることができます)。したがって、何を開発するべきかわからない場合は、いつでも私たちのプロジェクトに参加できます。必要です(メールは luna-lang.org で入手できます)。
ええ、弱い型と強い型はかなり漠然と定義されています。さらに、「強い型付け」の一般的な使用法に最も近いのは、型をキャストするのを困難にするものを参照することであるため、さらに強力な型システムを説明することはできません。持ち運べる体重が30ポンド未満だと弱いと言っているようなもので、もっと持ち上げることができる人は皆、「強い」という同じカテゴリーに分類されます。
だから私は定義を好む:
あなたのために物事を行うとはどういう意味ですか?さて、サーバントフレームワークでの画像変換APIの記述を調べてみましょう(Haskellでは、実際にそれを知る必要はありませんが、わかります...)
{-# LANGUAGE
TypeOperators,
DataKinds
#-}
import Codec.Picture
import Data.Proxy
import Network.Wai.Handler.Warp (run)
import Servant
import Servant.JuicyPixels
main :: IO ()
main = run 8001 conversion
これは、サーバントパッケージとサーバントへのJuicyPixelsプラグインを含むいくつかのモジュールが必要であり、プログラムの主なエントリポイントは、ポート8001でWarpバックエンドを使用するサーバーとして「変換」関数を実行することです。言語ビットを無視します。
conversion :: Application
conversion = serve (Proxy :: Proxy ConversionApi) handler
これは、変換関数がAPIがタイプ 'ConversionApi'と一致する必要があり、リクエストが関数handler
によって処理されるサーバーであることを示しています。
type ConversionApi
= ReqBody '[BMP, GIF, JPEG 50, PNG, TIFF, RADIANCE] DynamicImage
:> Post '[BMP, GIF, JPEG 50, PNG, TIFF, RADIANCE] DynamicImage
これはConvesionApi
タイプを指定しています。リスト '[BMP、GIF、JPEG 50、PNG、TIFF、RADIANCE]で指定された着信コンテンツタイプを受け入れ、それらをDynamicImageとして処理し、同じ範囲のコンテンツに変換されたDynamicImageを返す必要があることを示しています。タイプ。 :>が何を意味するかを正確に心配する必要はありません。今のところそれを幸せな魔法だと考えてください。
したがって、私の好ましい定義を考えると、弱く型付けされたシステムは、次のようなことを保証できます。
上記の定義を考えると、すべての高尚な目標ですが、厳密に型付けされたシステムとして認定するには十分ではありません。そして、この仕様に従うコードを実際に作成する際のhardの部分に到達する必要があります。本当にstrong型システムでは、次のように書きます:
handler = return
これで完了です。それだけですこれ以上記述するコードはありません。これは完全に動作するWebサーバーです(私が見逃したタイプミスを法として)。タイプは、定義してインポートしたタイプとパッケージ(技術的にはモジュール)からWebサーバーを作成するために必要なすべてのものをコンパイラーに伝えました。
では、これを主要なアプリケーションスケールでどのように学習するのでしょうか。まあ、それは実際に小規模なアプリケーションでそれらを使用することと大差ありません。絶対的な型は、それらに関連して書かれたコードの量を気にしません。
実行時の型検査は、おそらく回避したいと思うものです。これにより、型を単純化するのではなく、型がプロジェクトをより複雑に処理できるようになるため、メリットが大幅に削減されます。
そのため、ほとんどの場合、タイプで物事をモデル化する練習の問題です。物事をモデル化する(または物事を一般的に構築する)2つの主な方法は、ボトムアップとトップダウンです。トップダウンは、最高レベルの操作から始まり、モデルを構築するときに、モデリングを後で延期する部分があります。ボトムアップモデリングとは、基本機能から始めるのと同じように、基本操作から始めて、プロジェクトの操作を完全に取り込むまで、より大きなモデルを構築することを意味します。ボトムアップの方がより具体的であり、ビルドが速くなる可能性がありますが、トップダウンは、実際にどのように動作する必要があるかについて、より低レベルのモデルに通知する方がよい場合があります。
型とは、プログラムが文字通り数学にどのように関連するかであり、そのため、プログラムがどれほど複雑になるか、またはそれらについて「学ぶ」ことができる点に実際の上限はありません。高レベルの大学コース以外のリソースのほとんどすべてが、特定の言語で型がどのように機能するかに専念しているため、それも決定する必要があります。
私が提供できる限り、型は次のように階層化できます。
一般的に、このリストを下に行くほど、タイプが実行できることが多くなりますが、最下部では、成層圏に上昇し、空気が少し薄くなっています-パッケージエコシステムははるかに小さく、関連するライブラリを見つけるよりも、自分でもっと書く必要があります。大規模なプログラムを作成するのに十分な型システムを実際に理解する必要があるため、下に行くにつれてエントリへの障壁も高くなります。
私はScalaで書かれた大きなプラットフォームのコアチームに取り組み始めたところです。 Scalatra、Play、Slickなどの成功したオープンソースアプリケーションを調べて、動的データ形式とのやり取りに関する詳細な質問のいくつかをどのように処理するかを確認できます。
Scalaの強力なタイピングについて私たちが見つけた大きな利点の1つは、ユーザー教育にあります。コアチームは、意思決定を行い、タイプシステムでそれらの決定を実施することができます。設計原則にあまり慣れていないため、システムとやり取りする必要があり、コンパイラが修正し、コアチームはプルリクエストの内容を常に修正しているわけではありません。これは、大規模なシステムではhugeの利点です。
もちろん、すべての設計原則を型システムで適用できるわけではありませんが、型システムが強力であればあるほど、コンパイラーで実行できる設計原則が増えます。
また、ユーザーにとって使いやすいものにすることもできます。多くの場合、彼らは通常のコレクションまたはケースクラスを操作しているだけであり、ネットワークトランスポートの必要に応じて、JSONまたは自動的に何かに変換しています。
強力なタイピングは、無害化された入力と無害化された入力などを区別するのにも役立ち、セキュリティに役立ちます。
厳密な型指定は、型だけをテストする一連のテストを必要とせずに、テストを実際の動作に集中させるのにも役立ちます。これにより、テストがより楽しく、より集中し、したがってより効果的になります。
主な欠点は、言語と言語パラダイムに慣れていないことであり、それは時間とともに修正可能です。それ以外にも、努力する価値は十分にあることがわかりました。
直接的な回答ではありませんが(私はまだhaskellで+30.000 LOCコードベースに取り組んでいないため:( ..))、ぜひチェックしてください https://www.fpcomplete.com/business/resources/case-studies / 実際の業界設定でのhaskellの多くのケーススタディが特徴です。
もう1つの優れた記事はIMVUです。これは、彼らの経験がhaskellに変化することを説明しています http://engineering.imvu.com/2014/03/24/what-its-like-to-use-haskell/ 。
大規模なアプリケーションでの個人的な経験から、タイプシステムはveryを使用すると非常に役立ちます。物事をリファクタリングすることになると、真の力は本当に明白です。つまり、メンテナンスなどは、それほど気になりません。
一度にかなり多くの質問をしているので、私が推奨するリソースへのリンクをいくつかダンプします。
閉会の辞として、外の世界への対応に関してはいくつかの方法で行われます。 Aeson はJSON、 Esqueleto はSQLなど、タイプセーフを保証するライブラリがあります。
私が見たこと:
私はいくつかの大きなRuby Webアプリケーション(Rails)、1つの大きなHaskell Webアプリケーション、およびいくつかの小さなアプリケーションを使用してきました。その経験から、Haskellアプリケーションでの作業は多くのことを言わなければなりません。 Railsメンテナンスや学習曲線の低下などの点でより簡単です。これらの利点は両方ともHaskellの型システムと関数型プログラミングスタイルによるものだと思います。しかし、多くの場合とは異なり、型コントラクトの「静的」部分は、動的コントラクトを使用するときに得られるメリットがまだあるという点で、非常に便利です。
私が信じていること
Haskellプロジェクトがより優れたメンテナンス特性を実現するのに役立つと思われる主な機能のいくつかを提供するのに役立つ Contracts Ruby という素敵なパッケージがあります。コントラクトRubyは実行時にチェックを実行するので、高度なテスト収束と組み合わせると最適ですが、それでも、インライン注釈と型注釈の使用と同じ意図と表現の表現を提供しますHaskellなどの言語。
質問の答え
上記の質問に答えるために、Haskellや他の高度な型システムの言語に慣れることができる場所はたくさんあります。ただし、完全に正直に言うと、これらのドキュメントのソースはそれ自体は優れていますが、Ruby、Python、Java =と他のそのような言語。いずれの場合でも、 Real World Haskell は古くなっていますが、依然として優れたリソースです。
カテゴリー理論
Haskellを選択すると、カテゴリー理論について論じている大量の文献に出くわします。 IMHOカテゴリ理論は有用ですが、必須ではありません。 Haskellコミュニティで普及していることを考えると、タイプの賛否両論をカテゴリー理論の実用性についての感情と簡単に融合させることができます。それらが2つの異なるものであることを覚えておくと役立ちます。つまり、カテゴリ理論によって導かれる実装は、静的だけでなく動的に型付けされた言語でも実行できます(型システムが提供する利点を法として)。高度な型システムは一般にカテゴリー理論に拘束されておらず、カテゴリー理論は型システムに拘束されていません。
タイプの詳細
型を使用したプログラミングとその中のテクニック(楽しいので非常に迅速に行われます)についてさらに学習すると、型システムでより多くのことを表現したくなるでしょう。その場合、私は次のリソースのいくつかを調べて、これらの機能を備えた産業品質のツールが、使いやすいインターフェイス(Contracts Rubyなど)を公開するものにのみパッケージ化されることを望んでいることをツールベンダーに知らせます。
最初に、弱く型付けされたものと強く型付けされたもの、静的型と動的型付けの答えに混乱があるように感じます。提供されたOPをリンクすると、明確に区別されます。
強力な型システムは、魅力的なコンパイル時の制限または実行時の機能を持つ型システムです。
弱い型システムは、その制限または機能を欠く型システムです。
たとえば、C、C++、およびJavaは、変数がコンパイル時に型付けされるため、静的に型付けされます。ただし、CおよびC++は、言語がvoid *
ポインターおよびキャストを使用して制限をバイパスできるため、弱い型付けと見なされます。 . このトピックの詳細
この区別では、強い型付けがより良い場合があります。失敗が早いほど良い。
しかし、大きなプログラムを書く場合、型システムが重要な役割を果たすとは思いません。 Linuxカーネルは、Cおよびアセンブリで記述された1000万のLOCであり、非常に安定したプログラムと見なされており、私の200 Java行から数マイル離れている可能性があります。 「スクリプト言語」は、大規模なプログラムを書くことに関して悪い評判を被ります、それが不当であるという証拠があることもあります(Python Django、70k以上のLOCなど)
私の意見では、それはすべて品質基準に関するものです。大規模なアプリケーションのスケーラビリティに対する責任は、プログラマーとアーキテクト、およびアプリケーションをクリーンにしてテストし、十分に文書化する意志だけが負うべきです。