Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 操纵类型构造函数的参数顺序_Haskell_Types_Typeclass - Fatal编程技术网

Haskell 操纵类型构造函数的参数顺序

Haskell 操纵类型构造函数的参数顺序,haskell,types,typeclass,Haskell,Types,Typeclass,我写了这样的东西: instance Functor (Either e) where fmap _ (Left a) = Left a fmap f (Right b) = Right (f b) class Bifunctor f where bimap :: (a -> c) -> (b -> d) -> f a b -> f c d instance Bifunctor Either where bimap f _ (Le

我写了这样的东西:

instance Functor (Either e) where

   fmap _ (Left a) = Left a

   fmap f (Right b) = Right (f b)
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)
如果我希望
fmap
仅在
左侧
时更改该值,我该如何做同样的操作


我的意思是,我用什么语法来表示我用类型
或者b
而不是
或者a
。对于函数,您可以使用
flip
部分应用第二个参数,但这对
之类的类型构造函数也不起作用

最简单的方法可能是将其包装成
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
实例。否则,每个类型只能有一个实例

此外,根据您想要执行的操作,另一个选项是忽略
Functor
,并定义您自己的类型类,如下所示:

instance Functor (Either e) where

   fmap _ (Left a) = Left a

   fmap f (Right b) = Right (f b)
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)

显然,这个类的乐趣是普通的
函子的两倍。当然,你不能很容易地用它来创建一个Monad实例。

你基本上需要一个类型的“翻转”组合符。正如camccann所说,反转顺序的新类型包装器应该可以工作。请注意,您不能使用“type”同义词,因为它们可能没有部分应用。

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

为了使类型推断和类型类工作,类型中的参数顺序存在一定的位置偏差。已经证明,若我们在实例化类型类时允许对参数进行任意的重新排序,那个么类型推断将变得难以处理

您可以使用一个可以分别映射两个参数的类

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)
或者您可以使用一个组合器,如:

newtype Flip f a b = Flip { unFlip :: f b a }
这两个版本的通用版本在hackage的额外类别中提供。后者甚至包括
函子的一个实例(翻转任一a)
,因为
任一
都是
双函子
。(我可能应该修正这一点,只需要


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

相关:简而言之,目前在Haskell中这是不可能的。顺便说一句,这个问题的标题有些不清楚,但我不确定什么更好。我提出了一个更准确的标题。谢谢。我想不出比这更好的了。那么
newtype Flip t a b=Flip(t b a)
然后
instance Functor(Flip e)
?它不起作用:“所有实例类型必须是(t a1…an)形式,其中a1…an是类型变量”@m01:它起作用,但需要启用GHC语言扩展。在实践中,我会按照诺曼·拉姆齐的建议(不是双关语)去做,或者在我的答案中使用
Bifunctor
类。过度专业化的
Mirror
类型主要是为了说明这一想法。m01:您需要的扩展名为
FlexibleInstances
。您是否有“它已显示”的参考资料?