6

単一の単位値を持つタイプ(ここで正しい用語がわからない)、つまり事前定義された値を持つタイプのクラスはありますか?

class Unit a where
    unit :: a

instance Unit () where
    unit = ()

instance Unit (Maybe a) where
    unit = Nothing

...すべてのモノイド、MonadPlusなど。

クラスの別の名前は。かもしれないと思いますDefault。これは私にとって最近2回役に立ちました。

おそらく説得力のない例:

extract :: (Unit r)=> Reader r a -> a
extract r = runReader r unit

これは存在しますか?他の人はそれが役に立つかもしれないと思いますか?

4

3 に答える 3

9

はい、おそらく便利でしょう。実際、わずかに互換性のないバージョンはすべて役に立ちます。これはちょっと問題です。

そのようなクラスが何を意味するのかが明確ではないため、実際に使用するのは困難です。デフォルト値の選択肢が複数あるタイプにヒットすることは避けられず、インスタンスが提供するものがすぐに明確でない場合は、かなりのそもそもクラスを持つことのすべての利点を失います。

いくつかの例:

  • たとえばMonoid、ID要素がデフォルトであることが明らかに期待されます。しかし今、あなたは2つ以上の賢明なMonoidインスタンスを持っている非常に多くのタイプの問題に戻っています。デフォルトはInteger0または1ですか?の場合Monoid、標準ライブラリはnewtypeラッパーを使用しますが、ラッパーは扱いにくく、ラップされた型を操作するのが困難Monoidです。アクセスmconcatなどができるので問題なく動作しますが、デフォルト値だけでは面白いことはできません。

  • Functor「空の」値を持つ-likeタイプの場合、これは明らかなデフォルトを提供します。これは何MonadPlusをしているのかAlternative...そしてまた、と重複しています。Monoidメモリが私に役立つ場合、これらの3つのインスタンスが同一ではないタイプが少なくとも1つあります。複数の選択肢がある場合、どちらを選びますか?Monoidリストについて考えてみましょう。空のリストをIDとして、任意のリストを追加して、盲目的に追加できます。しかし、あなたのリストについては、アイデンティティとして持ち上げられたモノイドを与えるMonoidsこともできます。多くのファンクターには類似したインスタンスがありますが、常に両方であるとは限りません。したがって、リストにどちらを選択しても、概念的に他のファンクターと矛盾することになります。zipWith mappendrepeat memptyMonoidFunctor

  • のようなユニットタイプ()の場合、デフォルトを選択するのは難しくありません。しかし、列挙についてはどうでしょうか?最初のコンストラクターを選ぶのは理にかなっていますか?時々ですが、常にではありません。クラスを使用する人々はどのように知るのでしょうか?

  • どうBoundedですか?上記のいずれにも当てはまらない場合は、を使用できますminBound。ただし、上記のタイプの一部Boundedも同様である可能性があるため、デフォルトが最小値でない場合は、問題を混乱させる可能性があります。

基本的に、それが理にかなっているように見えるのに十分な重複があります...しかし実際には、ここでは少なくとも3つの異なる型クラスを念頭に置いており、それらを統合しようとすることはおそらく最初に思われるほど役に立ちません。


物事をもう少しうまく特定し、「デフォルト」値の明確で一貫性のある意味解釈を与えることができれば、型クラスを停止して何を考えなくMonoidても簡単に使用できるように、型クラスを再発明したり、別の既存のクラスを作成したりする必要はありません。デフォルト」が選択されます。しかし、私はそれを機能させることに私の希望を得ることができませんでした。

とは言うものの、標準型クラスでカバーされていない明らかに賢明なケースの1つは、のようなシングルトンです()。ほとんどの場合、これらはそれほど有用ではありません-明らかな理由で!-おそらくそのようなクラスがない理由です。ただし、そのようなクラスが非常に役立つ場所の1つは、型レベルのシェナニガンを含む何かをしているときです。そのような型は、型レベルと用語レベルの両方で単一の値を表すためです。したがって、そのような型のクラスを使用すると、型レベルの値を自由に操作し、それに付随する用語を思いつくので、たとえば、それに基づいて型クラスインスタンスを選択する可能性のある他の関数に渡すことができます。そのため、私は永続的に不完全なタイプハッカリーライブラリにこれらの線に沿ったクラスを持っています。例:

class TermProxy t where 
    term :: t

-- This makes explicit the lexical pun of () having type ().
instance TermProxy () where 
    term = ()

instance (TermProxy a, TermProxy b) => TermProxy (a, b) where 
    term = (term, term)

ただし、そのようなクラスが他のコンテキストで非常に役立つとは思えません。

于 2011-09-17T00:49:17.847 に答える
6

ある種のDefault型クラスを探しています。「デフォルト」がどうあるべきかについてのセマンティクスは議論の余地がありますが(そして、そこでの彼の貴重なコメントに対するCA McCannsの回答を受け入れることをお勧めします)、Defaultかなり一般的に使用されるパッケージからクラスを取得できますdata-default

クラスは次のとおりです。

-- | A class for types with a default value.
class Default a where
    -- | The default value for this type.
    def :: a
于 2011-09-17T00:51:52.020 に答える
3

新しいクラスを避けたい場合は、Enumクラスの観点からユニットを定義できます。

unit :: Enum a => a
unit = toEnum 0

または、Boundedクラスの方が良いかもしれません:

unit :: Bounded a => a
unit = minBound

これらは両方とも、ユニットタイプ(およびおそらく他の単一コンストラクタータイプ)に対して期待される結果を生成します。

*Main> unit :: ()
()

data-defaultクラス(別の回答で説明)と比較した場合の欠点は、インスタンスが少なく、特に[a]に対して[]を返すインスタンスがないことです。また、特にminBoundを使用する場合、結果は特定のタイプから期待できるものではありません。

*Main> unit :: Int
-2147483648

*Main> unit :: Char
'\NUL'

*Main> unit :: Bool
False
于 2011-09-18T01:22:57.167 に答える