【问题标题】:Applicative for a user defined type适用于用户定义的类型
【发布时间】:2020-03-09 18:40:07
【问题描述】:

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

我怎样才能让它工作?

【问题讨论】:

  • 你需要查看类型:在左边你有一个Choice (a -&gt; b),在右边你有一个(Choice a),它需要一个Choice b。所以返回Column A 确实不是一种选择。
  • “这不起作用”是什么意思?你得到什么错误?

标签: haskell applicative


【解决方案1】:

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

data Choice a = Bad a | Good a

您的 Functor 实例保留了值的污点,

instance Functor Choice where 
  fmap f (Bad  x)  =  Bad  (f x) 
  fmap f (Good x)  =  Good (f x) 

所以让我们对 Applicative 做同样的事情,不要吝啬我们的子句:

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)

正如在 cmets 中指出的那样,这将 Choice a 解释为与 Writer All a 同构,这意味着 Choice a 的值实际上就像 (Bool, a) 一样,(False, x) 对应于 Bad x(True, x) 对应于Good x。自然,我们只认为值是Good,如果它们的出处也是Good

【讨论】:

    【解决方案2】:

    如果ColumnA 被认为是某种错误,则不能让它包装a 值。确实。 (&lt;*&gt;) 的想法是它接受 Choice (x -&gt; y)Choice x,并返回 Choice y。但是如果你有一个 ColumnA 包装了一个 x -&gt; y 类型的函数,并且你在右手边有一个 Choice x,那么它应该返回一个 Choice y,而不是一个 Choice x

    你可以做的是用两个类型参数定义一个类型,例如:

    data Choice <b>a b</b> = ColumnA <b>a</b> | ColumnB <b>b</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 上定义的方式。

    【讨论】:

    • 我不打算回答,因为我认为您的方法可能是正确的。另一种解释是Choice aWriter Any a 同构。
    • @Willem Van Onsem - 我尝试运行您的代码,但无法编译。它不喜欢“(Choice a)”
    • @GilShafriri 是的,它在使用@-bindings 时遇到了微妙的类型行为。固定。
    • @Tim 这显然不是给定类型的正确方法,因为它将其更改为完全不同的类型。所以我添加了你暗示的答案。
    猜你喜欢
    • 2016-09-06
    • 1970-01-01
    • 2013-08-24
    • 1970-01-01
    • 2021-09-07
    • 2011-08-28
    • 1970-01-01
    • 2020-08-09
    • 1970-01-01
    相关资源
    最近更新 更多