TypeFamilies
,FunctionalDependencies
、MultiParamTypeClasses
で遊んでいます。そして、それはあたかもTypeFamilies
のように、他の2つの具体的な機能を追加していないようです。 (しかしその逆ではない)。しかし、タイプファミリーはかなり好きなので、私は何かが欠けているように感じます。マルチプラム型のクラスと関数の依存関係ができないタイプファミリは何ですか
TypeFamilies
では可能ではないと思われる変換機能のようなタイプ間の「オープン」関係。通常、標準型ファミリーで行われるであろうようなタイプ安全な擬似アヒルタイピング機構の一種であるタイプ、間
class Convert a b where
convert :: a -> b
instance Convert Foo Bar where
convert = foo2Bar
instance Convert Foo Baz where
convert = foo2Baz
instance Convert Bar Baz where
convert = bar2Baz
全射関係:MultiParamTypeClasses
で行わ。そして、あなたはすべての含まれているタイプのための新しいデータ型を宣言する必要があるが、そのようなデータを家族とTypeFamilies
を介して行うことができ箱なしの容器、用としてのタイプ、間
class HasLength a b | a -> b where
getLength :: a -> b
instance HasLength [a] Int where
getLength = length
instance HasLength (Set a) Int where
getLength = S.size
instance HasLength Event DateDiff where
getLength = dateDiff (start event) (end event)
全単射関係:MultiParamTypeClasses
とFunctionalDependencies
で完了例えば、newtype
である。どちらかそれまたは私はGHC 8に先立ってMultiParamTypeClasses
とFunctionalDependencies
を完了できないと思い単射型家族、持つ:
class Unboxed a b | a -> b, b -> a where
toList :: a -> [b]
fromList :: [b] -> a
instance Unboxed FooVector Foo where
toList = fooVector2List
fromList = list2FooVector
instance Unboxed BarVector Bar where
toList = barVector2List
fromList = list2BarVector
そして最後に、このようなpython2などの2つの種類と第三のタイプ間の全射の関係、またはjavaスタイルの除算関数は、MultiParamTypeClasses
も使用してTypeFamilies
で行うことができます。 MultiParamTypeClasses
とFunctionalDependencies
で行わ:
class Divide a b c | a b -> c where
divide :: a -> b -> c
instance Divide Int Int Int where
divide = div
instance Divide Int Double Double where
divide = (/) . fromIntegral
instance Divide Double Int Double where
divide = (. fromIntegral) . (/)
instance Divide Double Double Double where
divide = (/)
私も追加する必要がありますもう一つの事はあなただけのタイプを記述するために持っているように(とにかく上記の例のために)それはFunctionalDependencies
のように思えるとMultiParamTypeClasses
もかなりより簡潔であるということです一度、そしてあなたは、あなたがTypeFamilies
で行うようにインスタンスごとに入力する必要がダミーの型名を思い付くする必要はありません:対
instance FooBar LongTypeName LongerTypeName where
FooBarResult LongTypeName LongerTypeName = LongestTypeName
fooBar = someFunction
:
instance FooBar LongTypeName LongerTypeName LongestTypeName where
fooBar = someFunction
そうでなければ私は確信していない限り、実際にはTypeFamilies
と気にしないでください。FunctionalDependencies
とMultiParamTypeClasses
のみを使用してください。私が言う限りでは、私のコードをより簡潔に、一貫性のあるものにして(気にする拡張が少なくて済む)、オープンなタイプの関係や全単射の関係などの柔軟性を与えてくれるからです(潜在的に後者はGHC 8)。
タイプファミリは一般的に、特に型関数を実装するときに、基底関数よりもはるかに優れています。 – ErikR
また、読みやすさの問題もあります。 FunDepsで表現された '型F a = G(H(G a)(G a)) 'に相当するものはいくつかの補助型変数を含むいくつかの制約を必要とします。私がこのような制約を読んだとき、私は自分自身を機能的な形で表現しようとしていました。おそらく、これは私がプロローグよりも機能的なコードを読むのに慣れているからです。 – chi
@ErikRなぜですか?両方のオプションが実行可能である例は、型の解決に関して全く同じであり、私にとってはそうではないと思われるため、それは信じられないほど奇妙に思えます。 'FunctionalDependencies'や' MultiParamTypeClasses'の現在の実装やそれらの相互作用の欠点ですか?それとももっと根本的なものなのでしょうか?私は実際にはパフォーマンスの理由から、同じものに対しては半分の時間をかけて別の、もっと冗長な構文を使う必要がないのが良いと思うので、前者を期待しています。 – semicolon