操作参数的顺序以键入构造函数

mik*_*1aj 13 haskell types typeclass

我写了这样的东西:

instance Functor (Either e) where

   fmap _ (Left a) = Left a

   fmap f (Right b) = Right (f b)
Run Code Online (Sandbox Code Playgroud)

如果我只想fmap更改值,我该如何做同样的事情Left呢?

我的意思是,我使用什么语法来表示我使用的是type Either _ b而不是Either a _

C. *_*ann 9

不幸的是,我认为没有办法直接这样做.使用函数可以flip部分应用第二个参数,但这不适用于类型构造函数Either.

最简单的事情可能是将它包装在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)
Run Code Online (Sandbox Code Playgroud)

与包装newtype也创建一个单一类型的多个实例,例如为标准的方式SumProduct被实例Monoid为数字类型.否则,每种类型只能有一个实例.

另外,根据你想要做什么,另一种选择是忽略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)
Run Code Online (Sandbox Code Playgroud)

显然,该课程的乐趣是普通课程的两倍Functor.当然,你不能轻易地制作一个Monad实例.


Edw*_*ETT 6

您不能直接创建您要查找的实例。

为了使类型推断和类型类起作用,类型中的参数排序存在一定的位置偏差。已经证明,如果我们在实例化类型类时允许对参数进行任意重新排序,那么类型推断就会变得棘手。

您可以使用一个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)
Run Code Online (Sandbox Code Playgroud)

或者您可以使用Flip组合器,例如:

newtype Flip f a b = Flip { unFlip :: f b a }
Run Code Online (Sandbox Code Playgroud)

这两个的通用版本都可以在 hackage 的 category-extras 中找到。后者甚至包括一个Functor (Flip Either a)因为Either是 a的实例Bifunctor。(我可能应该解决这个问题,只需要一个PFunctor

最终,类型构造函数中参数的顺序对于确定可以实例化哪些类很重要。您可能需要使用 newtype 包装器(Flip如上所示)将参数放在它们需要有资格构造另一个类型类的实例的地方。这是我们为类型类约束的推断付出的代价。