【问题标题】:How to make instance of Applicative a certain data type如何使 Applicative 的实例成为某种数据类型
【发布时间】:2019-10-15 16:57:13
【问题描述】:

我正在阅读 Graham Hutton 关于 Haskell 的书,并且不知道如何在练习的一部分中进行。练习如下:

给定以下类型表达式

data Expr a = Var a | Val Int | Add (Expr a) (Expr a) deriving Show

包含某种类型 a 的变量,展示如何使这种类型成为 Functor、Applicative 和 Monad 类的实例。借助一个例子,解释一下>>=这个类型的操作符是做什么的。


我在定义 Applicative 的 <*> 运算符时遇到了问题。 <*> 的类型为:

(<*>) :: Expr (a -> b) -> Expr a -> Expr b

我不明白(Val n) &lt;*&gt; mx 是如何工作的,因为理论上我需要提供一个Expr b,但我只有一个Expr a 并且没有可转换的函数(a -&gt; b)。

我也不明白在(Add l r) &lt;*&gt; mx 的情况下该怎么办。


这是我的实现。

instance Functor Expr where
    --fmap :: (a -> b) -> Expr a -> Expr b
    fmap g (Var x) = Var (g x)
    fmap g (Val n) = Val n
    fmap g (Add l r) = Add (fmap g l) (fmap g r)


instance Applicative Expr where
    --pure :: a -> Expr a
    pure = Var

    -- <*> :: Expr (a -> b) -> Expr a -> Expr b
    (Var g) <*> mx = fmap g mx
    --(Val n) <*> mx = ???
    --(Add l r) <*> mx = ???

instance Monad Expr where
    -- (>>=) :: Expr a -> (a -> Expr b) -> Expr b
    (Var x) >>= g = g x
    (Val n) >>= g = Val n
    (Add l r) >>= g = Add (l >>= g) (r >>= g)


expr = Add (Add (Var 'a') (Val 4)) (Var 'b')

最后,我对 monad 中的 >>= 有疑问。这个操作符的想法是做一些诸如替换变量之类的事情?喜欢:

expr >>= (\x -> if x == 'a' then Val 6 else Var x) >>= (\x -> if x == 'b' then Val 7 else Var x)

【问题讨论】:

  • (Val n) &lt;*&gt; mx 中,n 的类型是什么? (注意&lt;*&gt;的类型)
  • 数据 Expr a = Var a |瓦尔诠释 | ...这是一个 Int
  • 啊抱歉我看错了我以为是Var...

标签: haskell monads applicative


【解决方案1】:

正如您正确指出的那样,在这种情况下:

(Val n) <*> mx = ???

你有:

Val n :: Expr (a -> b)
mx :: Expr a

并且您需要生成一个Expr b。你还记得这个案例吗:

fmap g (Val n) = ???

当你有:

g :: a -> b
Val n :: Expr a

您需要生成Expr b?您在那里找到了解决方案。

案例:

(Add l r) <*> mx

你有:

l :: Expr (a -> b)
r :: Expr (a -> b)
mx :: Expr a

并且您需要生成Expr b。如果你有一些函数可以使用lmx 并创建一个Expr b。这样的函数,如果存在的话,可能会有签名:

someFunc :: Expr (a -> b) -> Expr a -> Expr b

当然,对于someFunc l mxsomeFunc r mx,两者都是Expr b 类型,只使用一个会很可惜。如果有某种方法可以从两个Expr b 部分构造Expr b,那真的是蜜蜂的膝盖。

【讨论】:

    【解决方案2】:

    当您定义了pure(&gt;&gt;=) 时,(&lt;*&gt;) 的一种可能定义是

    (<*>) = Control.Monad.ap
    

    ap 在标准库中定义为

    ap :: Monad m => m (a -> b) -> m a -> m b
    ap mf mx = do
      f <- mf
      x <- mx
      pure (f x)
    

    事实上,(&lt;*&gt;) 的任何定义都必须等价于如果存在 Monad 实例。

    【讨论】:

      【解决方案3】:

      您在Val n 案例中的可用类型略有错误。您没有Expr a,而是Expr (a -&gt; b),根本没有ab(甚至没有来自a -&gt; b 的函数,因为Val 只包含Int)。事实上,这种情况很简单因为你周围没有有用的值:你可能做的唯一合理的事情是使用构造函数Val产生一个输出,因为你没有办法制造一个b 凭空而来。 Val 的类型可以专门化为Val :: Int -&gt; Expr b,很高兴你有一个Int,所以你可以这样写:

      (Val n) <*> mx = Val n
      

      【讨论】:

        猜你喜欢
        • 2019-06-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-06
        • 1970-01-01
        • 2019-10-04
        相关资源
        最近更新 更多