适用于用户定义的类型

问题描述 投票:1回答:2

我正在尝试为这种类型写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 

我如何使其起作用?

haskell applicative
2个回答
2
投票

如果认为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

但是FunctorApplicative的这种情况已经存在:这是在Either data type上定义的方式。


1
投票

让我们重命名您的数据构造函数,以正确表达您的意图,例如

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

© www.soinside.com 2019 - 2024. All rights reserved.