请考虑以下类型:
data SomeType m a = SomeType (m Integer) [a]
Run Code Online (Sandbox Code Playgroud)
我们可以使用以下代码轻松地将该类型作为Functor的实例:
instance Functor (SomeType m) where
fmap f (SomeType m lst) = SomeType m (map f lst)
Run Code Online (Sandbox Code Playgroud)
但是,如果相反SomeType类型的参数被交换:
data SomeType2 a m = SomeType2 (m Integer) [a]
Run Code Online (Sandbox Code Playgroud)
然后上面的实例定义不起作用.
有没有办法制作SomeType2Functor的实例?如果没有,那么haskell/ghc是否有任何新增功能可以实现?
pig*_*ker 20
我有偏见,但我认为这是一个很好的机会,可以使用Control.Newtype,这是一个仅仅是"cabal install newtype"的小工具.
这是交易.您想要翻转类型构造函数,以便在不同的参数中获得有趣的(例如).定义一个新类型
newtype Flip f x y = Flip (f y x)
Run Code Online (Sandbox Code Playgroud)
并将其添加到Newtype类中
instance Newtype (Flip f x y) (f y x) where
pack = Flip
unpack (Flip z) = z
Run Code Online (Sandbox Code Playgroud)
本Newtype类只是一个目录映射newtypes他们质朴的等价物,提供方便的工具包,例如op Flip是逆Flip:你不必记得你的说法.
对于有问题的问题,我们现在可以做这样的事情:
data Bif x y = BNil | BCons x y (Bif x y) deriving Show
Run Code Online (Sandbox Code Playgroud)
这是一个两参数数据类型,恰好在两个参数中都是函数式的.(或许,我们应该把它作为Bifunctor类的一个实例,但无论如何......)我们可以使它成为Functor两次:一次用于最后一个参数......
instance Functor (Bif x) where
fmap f BNil = BNil
fmap f (BCons x y b) = BCons x (f y) (fmap f b)
Run Code Online (Sandbox Code Playgroud)
......和第一次:
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))
Run Code Online (Sandbox Code Playgroud)
这里under p f是一个整洁的方式来表达op p . f . p.
我告诉你没有谎言:让我们试试吧.
someBif :: Bif Int Char
someBif = BCons 1 'a' (BCons 2 'b' (BCons 3 'c' BNil))
Run Code Online (Sandbox Code Playgroud)
然后我们得到
*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))
Run Code Online (Sandbox Code Playgroud)
在这种情况下,有很多方法可以将同一件事视为a Functor,所以我们必须发出一些声音来说明我们的意思.但是如果你对它有系统的话,噪音并不是那么多.