実際、戻り値の型の多相性は、型クラスの最も優れた機能の1つだと思います。しばらく使用した後、OOPスタイルモデリングに戻らない場合があります。
代数のエンコーディングを検討してください。Haskellには型クラスがありますMonoid
(無視しますmconcat
)
class Monoid a where
mempty :: a
mappend :: a -> a -> a
これをオブジェクト指向言語のインターフェースとしてどのようにエンコードできますか?簡単な答えはできません。これmempty
は、の型が(Monoid a) => a
別名であるため、戻り値の型ポリモーフィズムです。代数をモデル化する能力を持つことは、非常に便利なIMOです。*
「参照の透明性」に関する苦情から投稿を開始します。これは重要なポイントを提起します:Haskellは価値志向の言語です。したがって、式read 3
は値を計算するものとして理解する必要はなく、値としても理解できます。これが意味することは、実際の問題は戻り型の多相性ではなく、多相型([]
およびNothing
)を持つ値であるということです。言語にこれらが必要な場合、一貫性のためにポリモーフィックな戻り値の型が実際に必要です。
[]
型であると言えforall a. [a]
ますか?私はそう思う。これらの機能は非常に便利であり、言語をより簡単にします。
Haskellにサブタイプ多型[]
があれば、すべてのサブタイプになり[a]
ます。問題は、空のリストの型を多態的にしないでエンコードする方法がわからないことです。Scalaでどのように行われるかを検討してください(標準的な静的型付きOOP言語であるJavaで行うよりも短いです)
abstract class List[A]
case class Nil[A] extends List[A]
case class Cons[A](h: A. t: List[A]) extends List[A]
ここでも、Nil()
タイプNil[A]
**のオブジェクトです
戻り型ポリモーフィズムのもう1つの利点は、Curry-Howard埋め込みがはるかに簡単になることです。
次の論理定理を考慮してください。
t1 = forall P. forall Q. P -> P or Q
t2 = forall P. forall Q. P -> Q or P
これらをHaskellの定理として簡単に捉えることができます。
data Either a b = Left a | Right b
t1 :: a -> Either a b
t1 = Left
t2 :: a -> Either b a
t2 = Right
要約すると、私は戻り型のポリモーフィズムが好きで、値の概念が限られている場合にのみ参照の透明性を損なうと考えています(ただし、アドホック型クラスの場合はあまり説得力がありません)。一方、私はあなたのMRとタイプのデフォルトに関する説得力のあるポイントを見つけます。
*。ysdxのコメントでは、これは厳密には真実ではありません。代数を別の型としてモデル化することにより、型クラスを再実装できます。javaのように:
abstract class Monoid<M>{
abstract M empty();
abstract M append(M m1, M m2);
}
次に、このタイプのオブジェクトを渡す必要があります。Scalaには、これらのことを明示的に管理するオーバーヘッドの一部を回避する暗黙的なパラメーターの概念がありますが、私の経験ではすべてを回避するわけではありません。ユーティリティメソッド(ファクトリメソッド、バイナリメソッドなど)を別のFバインド型に配置することは、ジェネリックをサポートするOO言語で物事を管理する非常に優れた方法であることがわかりました。そうは言っても、タイプクラスを使って物事をモデル化した経験がなかったら、このパターンをひそかにしたかどうかはわかりません。
また、制限があり、そのままでは、任意の型の型クラスを実装するオブジェクトを取得する方法はありません。値を明示的に渡すか、Scalaの暗黙のようなものを使用するか、何らかの形式の依存関係注入テクノロジーを使用する必要があります。人生はいです。一方、同じ型に対して複数の実装を行えることは素晴らしいことです。何かが複数の方法でモノイドになります。また、これらの構造を別々に持ち歩くと、IMOはより数学的にモダンで建設的な感じになります。だから、私はまだこれを行うにはHaskellの方法を一般的に好むが、おそらく私の主張を誇張した。
戻り型ポリモーフィズムを持つ型クラスにより、この種の処理が容易になります。それはそれを行うための最良の方法だとは思わない。
**。 JörgW Mittagは、これは実際にはScalaでこれを行う標準的な方法ではないことを指摘しています。代わりに、次のような標準ライブラリを使用します。
abstract class List[+A] ...
case class Cons[A](head: A, tail: List[A]) extends List[A] ...
case object Nil extends List[Nothing] ...
これは、Scalaのボトム型と共変型パラメーターのサポートを利用しています。したがって、Nil
タイプNil
はnot Nil[A]
です。この時点では、Haskellからかなり離れていますが、Haskellがボトム型をどのように表しているかに注目するのは興味深いことです。
undefined :: forall a. a
つまり、これはすべてのタイプのサブタイプではなく、すべてのタイプのポリモーフィック(sp)メンバーです。
さらに多くの戻り型ポリモーフィズム。