如何为Haskell自定义类型MyEither实现Functor等类型类实例
问题解答
前置提醒
你自定义的MyEither里的Nothing构造子会和Prelude中Maybe类型的Nothing重名,编译会报错,有两种解决方式:
- 要么在代码文件头部添加导入声明隐藏Prelude的
Nothing:import Prelude hiding (Nothing) - 更稳妥的方案是给自定义构造子加前缀改为
MyNothing,避免命名冲突,以下示例均采用该命名方案。
问题1:新增空分支的处理逻辑
所有Functor、Applicative、Monad实例中,新增的空分支(MyNothing)都遵循短路中断语义,和MyLeft分支的处理逻辑一致:遇到该分支时直接返回自身,不执行任何映射、函数应用或者绑定操作,完全符合这三个类型类的定律要求。
问题2:deriving语句的使用规则
deriving语句不需要写在你手动实现的类型类实例中:
- 你现在写在
data定义尾部的deriving (Eq, Show),作用是让编译器自动为MyEither类型生成Eq和Show两个类型类的实例代码,不需要你手动实现。 - 只有当你需要让编译器自动派生某类型类的实例时才需要使用
deriving,你要手动实现的Functor、Applicative、Monad实例不需要加该关键字。
完整实例实现代码
-- 自定义类型定义 data MyEither a b = MyLeft a | MyRight b | MyNothing deriving (Eq, Show) -- 自动派生Eq、Show实例,不需要手动实现 -- Functor实例实现 instance Functor (MyEither a) where fmap _ (MyLeft x) = MyLeft x fmap f (MyRight y) = MyRight (f y) fmap _ MyNothing = MyNothing -- Applicative实例实现 instance Applicative (MyEither a) where pure = MyRight (MyLeft e) <*> _ = MyLeft e MyNothing <*> _ = MyNothing (MyRight f) <*> r = fmap f r -- Monad实例实现 instance Monad (MyEither a) where (MyLeft e) >>= _ = MyLeft e MyNothing >>= _ = MyNothing (MyRight x) >>= f = f x
内容的提问来源于stack exchange,提问作者Nightysky
相关产品推荐
相关产品推荐

