Haskell 使实例具有应用性

Haskell 使实例具有应用性,haskell,typeclass,applicative,Haskell,Typeclass,Applicative,舒尔如何制作更复杂类型的实例仍然不是百分之百的问题。请注意: data CouldBe a = Is a | Lost deriving (Show, Ord) 以Maybe为例,创建了一个函子的实例: instance Functor CouldBe where fmap f (Is x) = Is (f x) fmap f Lost = Lost 做这样的事: tupleCouldBe :: CouldBe a -> CouldBe b -> CouldB

舒尔如何制作更复杂类型的实例仍然不是百分之百的问题。请注意:

data CouldBe a = Is a | Lost deriving (Show, Ord) 
Maybe
为例,创建了一个
函子的实例:

instance Functor CouldBe where 
  fmap f (Is x) = Is (f x) 
  fmap f Lost   = Lost 
做这样的事:

tupleCouldBe :: CouldBe a -> CouldBe b -> CouldBe (a,b)
tupleCouldBe x y = (,) <$> x <*> y
tupleCouldBe::CouldBe a->CouldBe->CouldBe->CouldBe(a,b)
tupleCouldBe x y=(,)x y

可能是
需要是
Applicative
的一个实例,但您将如何做到这一点?当然,我可以查找并复制它,但我想了解它背后的过程,最后以CouldBe的
实例
声明结束。

您只需按照以下类型写出它:

instance Applicative CouldBe where
   {- 
        Minimal complete definition:
          pure, ((<*>) | liftA2)

      pure :: a -> f a 
      pure :: a -> CouldBe a

      liftA2 :: (a -> b -> c) -> f a -> f b -> f c 
      liftA2 :: (a -> b -> c) -> CouldBe a -> CouldBe b -> CouldBe c 
   -}
    pure a = fa
        where
        fa = ....

    liftA2 abc fa fb = fc
        where
        fc = ....
我们的工具集是

Is   :: a -> CouldBe a
Lost :: CouldBe a
但我们也可以使用模式匹配,例如

couldBe   is   lost  (Is a)    = is a
couldBe   is   lost  (Lost)    = lost
couldBe :: ? -> ? -> CouldBe a -> b
couldBe :: ? -> b -> CouldBe a -> b
couldBe :: (a -> b) -> b -> CouldBe a -> b
所以

匹配

    Is   :: a -> CouldBe a
所以我们定义

    pure a = Is a
然后,对于
liftA2
,我们遵循以下数据案例:

    -- liftA2 :: (a -> b -> c) -> f a -> f b -> f c 
    -- liftA2 :: (a -> b -> c) -> CouldBe a -> CouldBe b -> CouldBe c
    liftA2 abc Lost    _     = ...
    liftA2 abc  _     Lost   = ...
    liftA2 abc (Is a) (Is b) = fc
        where
        c = abc a b
        fc = ....     -- create an `f c` from `c`: 
                      -- do we have a `c -> CouldBe c` ?
                      -- do we have an `a -> CouldBe a` ? (it's the same type)
但在前两种情况下,我们没有
a
b
;所以我们必须想出一个
可能是c
的从无到有。我们的工具集中也有这个工具


完成所有缺失的部分后,我们可以将表达式直接替换到定义中,消除所有不需要的中间值/变量。

首先写下需要定义的函数,使
可以成为
应用程序的一个实例,并带有其类型签名(专门从事
可能是
)。如果让类型来指导你,你应该会发现只有一个合理的解决方案。你的
Functor
实例向你展示了如何处理
丢失的
。模式尽可能匹配,然后以类型检查的唯一方式构造结果。这通常有效。从逻辑上讲,我会定义
>,对吗?我认为pure应该像
pure a=Is a
一样简单,但是
不需要更多的变体…尝试
两侧的模式匹配;这应该给出四种不同的情况。然后使用@RobinZigmond的建议,针对每种情况“遵循类型”。另外一件可能有帮助的事情是键入漏洞:如果你不知道,请键入漏洞现在把什么放在某个地方,使用下划线
,GHC会给你应该在那里的类型。它们在这种“遵循类型”的情况下非常有用。请注意,你的
可能与Haskell的内置
可能
类型同构,所以任何时候你都想知道如何为你的例如,您可以查看
Maybe
的对应实例是如何编写的。
    pure a = Is a
    -- liftA2 :: (a -> b -> c) -> f a -> f b -> f c 
    -- liftA2 :: (a -> b -> c) -> CouldBe a -> CouldBe b -> CouldBe c
    liftA2 abc Lost    _     = ...
    liftA2 abc  _     Lost   = ...
    liftA2 abc (Is a) (Is b) = fc
        where
        c = abc a b
        fc = ....     -- create an `f c` from `c`: 
                      -- do we have a `c -> CouldBe c` ?
                      -- do we have an `a -> CouldBe a` ? (it's the same type)