議論の順序を操作して、コンストラクターを入力します
質問
私はこのようなことを書きました:
instance Functor (Either e) where
fmap _ (Left a) = Left a
fmap f (Right b) = Right (f b)
必要に応じて同じことをするにはどうすればよいですか fmap
値を変更する場合のみ Left
?
つまり、タイプを使用していることを示すためにどの構文を使用していますか Either _ b
それ以外の Either a _
?
解決
残念ながら、それを直接行う方法はないと思います。機能を使用すると、使用できます flip
2番目の引数を部分的に適用するが、それは次のような型コンストラクターでは機能しません Either
.
最も簡単なことは、おそらくそれをaで包むことです newtype
:
newtype Mirror b a = Mirrored (Either a b)
instance Functor (Mirror e) where
fmap _ (Mirrored (Right a)) = Mirrored $ Right a
fmap f (Mirrored (Left b)) = Mirrored $ Left (f b)
包みます newtype
また、単一のタイプの複数のインスタンスを作成する標準的な方法でもあります。 Sum
と Product
のインスタンスであること Monoid
数値タイプ用。それ以外の場合は、タイプごとに1つのインスタンスしか持てません。
さらに、それが何をしたいのかに応じて、別のオプションは無視することです Functor
次のような独自のタイプクラスを定義します。
class Bifunctor f where
bimap :: (a -> c) -> (b -> d) -> f a b -> f c d
instance Bifunctor Either where
bimap f _ (Left a) = Left $ f a
bimap _ g (Right b) = Right $ g b
instance Bifunctor (,) where
bimap f g (a, b) = (f a, g b)
明らかに、そのクラスはレギュラーの2倍の楽しいです Functor
. 。もちろん、あなたは作ることはできません Monad
それから非常に簡単にインスタンスします。
他のヒント
探しているインスタンスを直接作成することはできません。
タイプの推論とタイプクラスが機能するためには、タイプの引数の順序付けに特定の位置的バイアスがあります。タイプクラスをインスタンス化するときに引数の任意の並べ替えを許可した場合、そのタイプの推論が扱いやすくなることが示されています。
aを使用できます Bifunctor
両方の引数を個別にマッピングできるクラス。
class Bifunctor f where
bimap :: (a -> b) -> (c -> d) -> f a c -> f b d
first :: (a -> b) -> f a c -> f b c
second :: (c -> d) -> f a c -> f a d
first f = bimap f id
second = bimap id
instance Bifunctor Either where
bimap f _ (Left a) = Left (f a)
bimap _ g (Right b) = Right (g b)
instance Bifunctor (,) where
bimap f g (a,b) = (f a, g b)
または、aを使用できます Flip
Combinator like:
newtype Flip f a b = Flip { unFlip :: f b a }
これらの両方の一般化されたバージョンは、ハッケージ上のカテゴリエクストラで入手できます。後者には、インスタンスも含まれています Functor (Flip Either a)
なぜなら Either
aです Bifunctor
. 。 (私はおそらくそれを修正する必要があります PFunctor
)
最終的に、タイプコンストラクターの引数の順序は、どのクラスをインスタンス化できるかを決定する上で重要です。 NewTypeラッパーを使用する必要がある場合があります( Flip
上記)別のタイプクラスのインスタンスを構築するために資格を得るために必要な議論を置く。これは、型クラスの制約の推論に対して支払う価格です。
本質的にタイプに「フリップ」コンビネーターが必要です。 Camccannが言うように、順序を反転させる新しいラッパーが機能するはずです。 「タイプ」の同義語は、部分的に適用されない可能性があるため、使用できないことに注意してください。