32

どうやら、Alexander Stepanov はインタビューで次のように述べています。

「OOP [オブジェクト指向プログラミング] は技術的に不健全だと思います。単一の型で変化するインターフェイスの観点から世界を分解しようとします。実際の問題に対処するには、マルチソートされた代数 (複数の型にまたがるインターフェイスのファミリ) が必要です。[強調を追加]

OOP に関する彼の発言を少し無視して、彼の簡潔な定義を超えた「マルチソート代数」とは何ですか? また、それらがどのように使用されているか (選択した言語で) の実用的な例を挙げていただけますか?

4

3 に答える 3

23

彼はジェネリック プログラミングについて話していたと思います(彼は という用語を作り出しました)。STL についてのこの話の文脈で意味されているか、または「一般的に」次の意味で意味されているかは関係ありません。

  1. すべての(できれば複数の)タイプ(したがってマルチソート) に適合する何かを記述する一種のインターフェースに対するプログラミング、...
  2. ...それらがいくつかのプロパティを持っている場合、多くの場合、そのタイプの要素に対するいくつかの操作の性質に関するものです(したがって、代数)。

(1) を行うには、型をパラメーターとして受け取るプログラムを指定する方法、つまりポリモーフィズムが必要であり、(2) を行うには、その型に特定の操作を実行させたいこと伝える方法が必要です。 (そして、それらを表現できれば、プロパティ)。実際には、プログラムが操作するデータの構造によってプログラムをパラメーター化しています。パラダイムは、いくつかの場所で境界ポリモーフィズム、データ型ジェネリック プログラミングなどと呼ばれています。これは、言語がそのアイデアを実装する方法について異なる概念を持っていることを反映しています。

  • C++ の場合、少なくとも Stepanov にとっては、これはテンプレートに対応しているように見えます (ただし、これを最適に行う方法についてのアイデアはまだ発展途上にあります)。
  • OO 言語 (Generic Java、C#) の場合、型パラメーターの制約は通常、サブタイプの境界 (「境界付きワイルドカード」...) を使用して表現されます。
  • Haskell または Scala の場合、(それぞれ、および同様に)型クラスまたはImplicitがあります。
  • 言語の ML ファミリは、モジュールを使用してこれを行うことを好みます。
  • 多くの証明アシスタント(「神への正直な」プロパティを型として表現できる) が型クラスのフレーバーを開発したことに注意してください: Isabelle、Coq、Matita はそのような例です。

Stepanov はちょうど本全体を共同執筆したばかりであり、ライブラリの徹底的な開発を行っており、それはまさに(私が思うに) 彼の意図を具現化しています。したがって、 C++の例が必要な場合は、間違いなくここを参照する必要があります。これは、 object ではなくインターフェースに対してコーディングするという現在一般的なアドバイスよりもはるかに進化していることにも注意してください。

「実際の例」とは、「どのように」または「なぜ」それを使用するのかを意味するかどうかはわかりません. 「なぜ」に対して似顔絵のように簡単な答えを与えるには、ありふれたポリモーフィズムのように、コードを再利用できる汎用性が優れています。しかし、もっと重要なこと:

  1. すべての型で動作しなければならないポリモーフィック コードでは、多くの場合、面白いことは何もできませんが、制限されたインターフェイスを使用すると、よりリッチなプログラムを作成できます。

  2. そのインターフェイスがデータにどのように適合するかを指定することで、ニーズに合った要素だけを選択するタイプ セーフな方法が得られます。たとえば、リダクション関数を適用する順序が問題にならない場合にのみ、リダクション演算子 (Python と Hadoop の関数型言語) が並列化可能あるreduceことをおそらく知っているでしょう (しません)。「連想操作を備えた型」という概念があれば、その上で並列リダクションを呼び出せることがわかります。fold+xminand

  3. 汎用性によって発生するオーバーヘッドは、コンパイル時に発生します。たとえば、テンプレートは伝説的に高速です

ジェネリック Java を見たことがあれば、たとえばComparableジェネリック インターフェイスを見てください。それは 1 つの操作のみを定義しますが、それが作るコントラクトは、基本的ではありますが、非常に代数的な風味があります。私は引用します:

数学的に傾いている場合、特定のクラス C の自然な順序を定義する関係は次のとおりです。

  {(x, y) such that x.compareTo((Object)y) <= 0}.

この合計注文の商は次のとおりです。

  {(x, y) such that x.compareTo((Object)y) == 0}.

商が C 上の同値関係 > であり、自然順序付けが C 上の全順序であることは、compareTo の契約からすぐにわかります。

これで、最小値を 1 回選択するメソッドを作成し、このインターフェイスに適合する任意の型に使用できます

 public static <T extends Comparable<T>> T min (T x, T y) {
   if (x.compare(y) < 0) x; else y;
 }

当然、プログラム構成がその概念を実装する方法は大きく異なるため、使いやすさと表現力に関して得られるものも異なります。おそらく、C++ や Java などの OO 言語だけでデータジェネリック プログラミングを判断するべきではありませんが、モジュールの割り当てや型クラスの自動インスタンス生成から始めるには、すでに多くのことを書きすぎています。

于 2010-12-26T21:53:59.217 に答える
11

遅くなりましたが、参考になれば幸いです。ユーザーhuitseekerは、ソフトウェア設計の観点から優れた回答を書きました。数学の観点からあなたの質問に答えたいと思います。ソフトウェアの世界に飛び込む前は、アレックス ステパノフは数学者であり、抽象代数と普遍代数を研究していました。そして彼はしばしば、厳密な数学的基礎をソフトウェアとアルゴリズムの設計の世界に持ち込もうとしました。彼の著書「数学から汎用プログラミングへ」および「プログラミングの要素」で、彼はこの設計手法を提唱しています。代数構造とソフトウェア設計の概念を混合するという彼のアイデアは、 の概念で実現されましたgeneric programming。そして今、彼の引用について話しましょう:

実際の問題に対処するには、マルチソートされた代数 (複数の型にまたがるインターフェイスのファミリ) が必要です。

私の意見では、彼がここで言及したかった主な概念は 2 つあります。それは、抽象データ型( ADT) と代数構造の概念です。最初のコンセプト: ADT. ADT- データ型がそのセマンティックによってのみ定義されるデータ型の数学的モデルです。Stepanov は、OOP の意味でADTのアイデアを、のアイデアと対比させました。objectオブジェクトにはデータと状態が含まれますが、ADT には含まれません。ADT -データとbehavioural abstractionoperation cluster相互作用を説明する です。振る舞いの抽象化は、抽象データ型の代数的仕様によって完全に記述されます。これについては、元のLiskov と Zillesの論文で詳しく読むことができます。ウィリアム R. クックによるオブジェクト指向プログラミングと抽象データ型の比較。

(免責事項:この段落は「数学的でそれほど重要ではない」ため、スキップできます) 最初に、いくつかの用語を明確にしたいと思います。私が について話すとき、algebraic structureそれは代数と同じです。この言葉algebraは、代数構造にもよく使用されます。より正確に言えば、代数構造 (algebra) について話すときは、通常、代数理論よりも代数を意味します。代数の多様性という概念があります。これは、あるカテゴリのオブジェクトに関する代数構造の概念がいくつかあるためです。定義により、algebraic theory(algebra over it) は、これらの操作が満たさなければならない操作と法則の仕様で構成されます。これは、使用する代数構造の作業定義であり、この定義は、ステパノフが暗黙のうちに引用で言及したと思います。

Stepanov が言及したかった2 番目の概念は、ADT の最も興味深い特性です。ADT は として直接モデル化できますmany-sorted algebraic structures。もっと正式に話しましょう。代数構造 - carrier set1 つまたは複数の有限演算が定義された です。これらの操作は通常、1 つのセットに対してではなく、複数のセットに対して定義されます。たとえば、文字列連結をモデル化する代数を定義してみましょう。この代数は、文字列の 1 つのセットではなく、文字列セットSと自然数セットNの 2 つのセットで定義されます。これは、文字列をそれ自体と有限回数連結できる操作を定義できるためです。Sしたがって、この操作は、異なる基になる (キャリア) セットに属する 2 つのオペランドを使用します。N. のセットと呼ばれる代数でこれらの異なるオペランド (それらの型) を定義するセットsortsSort型の代数的アナログです。マルチソート代数と呼ばれる、複数のソートを持つ代数。普遍代数では、asignatureは代数構造を特徴付ける演算のリストです。多ソート代数構造は、任意の数の定義域を持つことができます。種類は署名の一部であり、さまざまなドメインの名前の役割を果たします。多ソート署名はまた、多ソート代数構造の関数と関係がどのソートで定義されるかを規定します。1 種類の代数の場合、署名は集合であり、その要素は操作と呼ばれ、それぞれにアリティと呼ばれる基数 (0、1、2、…) が割り当てられます。マルチソート代数のシグネチャは、次のように定義できます。Σ = (S,OP,A)、ここでS– ソート名 (型) のセットOP– 操作名とアリティAのセットただし、アリティが単なる自然数 (長さリストの) 1 つの出力ソートと一緒に。これで、抽象データ型の代数仕様をトリプルとして作成できます。ADT

ADT = (N, Σ, E)

、ここでN- 抽象データ型の名前Σ = (S,OP,A)- マルチソート代数構造の署名 - 署名E = {e1, e2, …,en}内の等値の有限集合。ご覧のとおり、ADT の厳密な数学的記述ができました。数学では、並べ替えられた代数構造は、少しの努力で回避できる場合でも、便利なツールとしてよく使用されます。一般化を明示的に実行するのは簡単であるため、多ソート代数構造が厳密な方法で定義されることはめったにありません。これが、多ソート代数の理論をソフトウェア設計にうまく適用できる理由です。

Alex Stepanov は、OOP よりも ADT とジェネリック プログラミングを好むと言いたかったのです。これにより、厳密な数学的/代数的基礎を備えたプログラムを作成できるからです。彼の努力にとても感謝しています。代数的設計は常に正確で、厳密で、美しく、単純であり、より良い抽象化をもたらすことは誰もが知っています。

于 2015-05-15T07:58:06.600 に答える