我正在尝试为这种类型写Applicative
data Choice a = ColumnA a | ColumnB a
我写了一个Functor实例:
instance Functor Choice where
fmap f (ColumnA a ) = (ColumnA (f a) )
fmap f (ColumnB a ) = (ColumnB (f a) )
现在我要写Applicative,其中将ColumnB
视为“正确值”,而将ColumnA
视为某种错误。
我尝试过
instance Applicative Choice where
pure = ColumnB
ColumnB f <*> r = fmap f r
ColumnA f <*> _ = ColumnA f --- this does not work
我如何使其起作用?
如果认为ColumnA
是某种错误,则不能让它包装a
值。确实。 (<*>)
的概念是它需要一个Choice (x -> y)
和Choice x
,并返回一个Choice y
。但是,如果您有一个包装了ColumnA
类型的函数的x -> y
,并且在右侧有一个Choice x
,那么它应该返回一个Choice y
,而不是Choice x
。
您可以做的是用两个类型参数定义一个类型,例如:
data Choice a b = ColumnA a | ColumnB b
然后您仅在ColumnB b
数据构造函数上执行映射:
instance Functor (Choice a) where
fmap _ (ColumnA e) = ColumnA e
fmap f (ColumnB x) = ColumnB (f x)
然后我们可以将Applicative
实例定义为:
instance Applicative (Choice a) where
pure = ColumnB
ColumnB f <*> ColumnB x = ColumnB (f x)
ColumnA e <*> _ = ColumnA e
_ <*> ColumnA e = ColumnA e
但是Functor
和Applicative
的这种情况已经存在:这是在Either
data type上定义的方式。
让我们重命名您的数据构造函数,以正确表达您的意图,例如
Either
您的data Choice a = Bad a | Good a
实例使值受到污染,
Functor
所以让我们对Applicative进行相同的操作,而不必对我们的子句有所顾忌:
instance Functor Choice where fmap f (Bad x) = Bad (f x) fmap f (Good x) = Good (f x)
[如注释中所指出,这将
instance Applicative Choice where pure x = Good x -- fmap f == (pure f <*>) is the Law Good f <*> Good x = Good (f x) Good f <*> Bad x = Bad (f x) Bad f <*> Good x = Bad (f x) Bad f <*> Bad x = Bad (f x)
解释为与Choice a
同构,这意味着Writer All a
值的确类似于Choice a
,其中(Bool, a)
对应于(False, x)
,Bad x
对应于(True, x)
C0]。当然,如果其来源中的所有内容也均为Good x
,则仅将值视为Good
。