我有偏见,但我认为这是一个利用的好机会控制.Newtype http://hackage.haskell.org/packages/archive/newtype/0.2/doc/html/Control-Newtype.html,一个小工具包,只需“cabal install newtype”即可。
事情是这样的。您想要翻转类型构造函数以了解不同参数中的功能(例如)。定义一个新类型
newtype Flip f x y = Flip (f y x)
并将其添加到Newtype
因此类
instance Newtype (Flip f x y) (f y x) where
pack = Flip
unpack (Flip z) = z
The Newtype
class 只是一个将新类型映射到其未修饰的等效项的目录,提供方便的工具包,例如op Flip
是的倒数Flip
: 你不需要记住你叫它什么。
对于所讨论的问题,我们现在可以这样做:
data Bif x y = BNil | BCons x y (Bif x y) deriving Show
这是一个双参数数据类型,恰好在两个参数中都是函数。 (也许,我们应该将其设为 Bifunctor 类的实例,但无论如何......)我们可以将其设为Functor
两次:最后一个参数一次...
instance Functor (Bif x) where
fmap f BNil = BNil
fmap f (BCons x y b) = BCons x (f y) (fmap f b)
...第一次:
instance Functor (Flip Bif y) where
fmap f (Flip BNil) = Flip BNil
fmap f (Flip (BCons x y b)) = Flip (BCons (f x) y (under Flip (fmap f) b))
where under p f
是一个简洁的表达方式op p . f . p
.
我没有告诉你任何谎言:让我们尝试一下。
someBif :: Bif Int Char
someBif = BCons 1 'a' (BCons 2 'b' (BCons 3 'c' BNil))
然后我们得到
*Flip> fmap succ someBif
BCons 1 'b' (BCons 2 'c' (BCons 3 'd' BNil))
*Flip> under Flip (fmap succ) someBif
BCons 2 'a' (BCons 3 'b' (BCons 4 'c' BNil))
在这种情况下,同一件事确实可以有很多种方式被视为Functor
,所以我们必须发出一些声音来表达我们的意思,这是正确的。但如果你系统地对待它,噪音并没有那么大。