You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Either构造为针对第一个类型参数的Functor

如何让Either的Functor实例作用在第一个类型参数上?

嘿,这个问题戳中了Haskell里Functor类型类一个很关键的点——类型构造器的kind匹配!咱们先回顾默认情况,再一步步实现你想要的效果。

首先,默认的Either是二元类型构造器,它的kind是* -> * -> *,而Functor要求的是一元类型构造器(kind * -> *)。所以标准库的做法是固定第一个类型参数,得到Either a(kind * -> *),这样fmap就只能作用在Right包裹的值上:

instance Functor (Either a) where
    fmap f (Right x) = Right (f x)
    fmap f (Left x) = Left x

而你想要让fmap作用在Left包裹的值上,也就是固定第二个类型参数,让第一个参数成为fmap的映射目标。但直接给Either写另一个实例是行不通的——Haskell不允许同一个类型构造器有多个同类型类的实例(除非用扩展,那是另一个话题了)。

解决办法很简单:用newtype给Either做一个「参数翻转」的包装,把原来的Either a b转换成以b为固定参数、a为可变参数的一元构造器。

具体实现步骤

  1. 定义一个newtype,翻转Either的参数顺序:
newtype LeftFunctorEither b a = LeftFunctorEither (Either a b)

这里LeftFunctorEither b a对应的底层类型是Either a b——也就是说,LeftFunctorEither b是一个一元类型构造器(kind * -> *),固定了原来Either的第二个参数b,剩下的a就是我们要映射的目标。

  1. 给这个newtype实现Functor实例:
instance Functor (LeftFunctorEither b) where
    fmap f (LeftFunctorEither (Left x)) = LeftFunctorEither (Left (f x))
    fmap f (LeftFunctorEither (Right x)) = LeftFunctorEither (Right x)

这样一来,fmap就会精准作用在Left包裹的值上,完全符合你想要的行为!

额外小技巧

如果你不想自己写这个newtype,可以用base库中Data.Functor.Flip这个现成的类型,它的作用就是翻转二元类型构造器的参数顺序:

import Data.Functor.Flip

-- 直接用Flip包装Either实现目标实例
instance Functor (Flip Either b) where
    fmap f (Flip (Left x)) = Flip (Left (f x))
    fmap f (Flip (Right x)) = Flip (Right x)

效果和我们自定义的newtype完全一致,只是少写了几行代码~

总结一下:核心就是通过newtype调整类型构造器的参数顺序,让我们想要映射的类型参数成为Functor要求的「可变参数」,从而实现自定义的fmap行为。

内容的提问来源于stack exchange,提问作者kishlaya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:36:35