当你写下你的实例时,首先明确地写出类型:
data MyEither a b = MyLeft a | MyRight b | MyNothing
deriving (Eq, Show)
instance Functor (MyEither a) where
-- fmap :: Functor f => (b -> c) -> f b -> f c
-- fmap :: (b -> c) -> MyEither a b -> MyEither a c
(我将在此处使用MyNothing 以防止与Maybe 的Nothing 混淆)。
现在我们准备好根据数据类型定义枚举所有可能性:
fmap bc (MyLeft aValue) = result where
-- bc :: b -> c
-- MyLeft aValue :: MyEither a b
-- result :: MyEither a c
.....
这里我们必须生成一个MyEither a c 类型的值作为结果。 bc 函数在这里没有用,因为我们只能访问 a 类型的值 aValue :: a:
MyLeft aValue :: MyEither a b
--------------------------------
aValue :: a
因此我们这里有两种可能:
-
result = MyLeft aValue 将构造一个新值,这次是由类型签名确定的 MyEither a c 类型;或
-
result = ...。
填写点,并在 1. 和 2 之间进行选择,完成此子句的定义,fmap bc (MyLeft aValue) = ...。 (但请参阅本文底部的重要说明)
下一个可能性是
fmap bc (MyRight bValue) = ...
这一次我们确实可以访问b 类型的值,所以函数bc 可以派上用场,因为
bValue :: b
bc :: b -> c
-------------------------
bc bValue :: c
和
cValue :: c
--------------------------------
myRight cValue :: MyEither a c
因此,这个子句的自然定义是
fmap bc (MyRight bValue) = MyRight cValue
where
cValue = ....
当然,第二个选项在技术上也是可能的@ 在这里构造一个MyEither a c 值,因为我们在这里完全无法访问任何a 类型值......除了undefined。
现在只剩下一种可能性,对于 MyEither a b 类型的值,我们的 fmap 必须根据其类型签名(记住,fmap :: (b -> c) -> MyEither a b -> MyEither a c)处理。而那个值是...
fmap bc MyNothing =
同样,我们必须生成一个MyEither a c 类型的值作为结果。这次我们无法访问任何类型的值,既不是b,也不是a。所以除了return没有别的选择了……
.......
(当然没有undefined 的使用)。完成定义。
我希望您现在能够根据需要完成其他定义。
重要更新:上面提到的那些选择实际上根本没有选择。如果我们所关心的只是做出适合该类型的定义,那么这些可能性确实存在。但是,Functor 等实例也必须是合法的。例如函子定律是
fmap id === id
fmap (f . g) === fmap f . fmap g
在每种情况下,只有一种可能性不会违反法律。特别是,fmap id (MyLeft _) = MyNothing 打破了第一函子定律。