如何使 Applicative 的实例成为某种数据类型
How to make instance of Applicative a certain data type
我正在阅读关于 Haskell 的 Graham Hutton 的书,不知道如何在练习的一部分中进行。习题如下:
给定以下类型表达式
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) <*> mx
是如何工作的,因为理论上我需要提供一个 Expr b
,但我只有一个 Expr a
并且没有转换功能 (a -> b
).
我也不明白在(Add l r) <*> 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)
当您定义了 pure
和 (>>=)
时,(<*>)
的一种可能定义是
(<*>) = 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)
事实上 (<*>)
的任何定义都必须等同于 Monad
实例。
正如您正确注意到的那样,在这种情况下:
(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
。如果你有一些函数可以接受 l
和 mx
并创建一个 Expr b
。这样的函数,如果存在的话,可能会有签名:
someFunc :: Expr (a -> b) -> Expr a -> Expr b
当然,someFunc l mx
和someFunc r mx
都是Expr b
类型,只用一个就可惜了。如果有某种方法可以从两个 Expr b
部分 构建 一个 Expr b
,那真的是蜜蜂的膝盖。
您对 Val n
案例中可用的类型有轻微的误解。您没有 Expr a
,而是 Expr (a -> b)
,根本没有 a
或 b
(甚至 a -> b
中的函数也没有,因为 Val
只包含一个 Int
)。事实上,这种情况很简单 因为 你周围没有有用的值:你可能做的唯一合理的事情就是使用构造函数 Val
产生输出,因为你有无法凭空制造 b
。 Val
的类型可以专门化为 Val :: Int -> Expr b
,幸运的是,你有一个 Int
,所以你可以写:
(Val n) <*> mx = Val n
我正在阅读关于 Haskell 的 Graham Hutton 的书,不知道如何在练习的一部分中进行。习题如下:
给定以下类型表达式
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) <*> mx
是如何工作的,因为理论上我需要提供一个 Expr b
,但我只有一个 Expr a
并且没有转换功能 (a -> b
).
我也不明白在(Add l r) <*> 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)
当您定义了 pure
和 (>>=)
时,(<*>)
的一种可能定义是
(<*>) = 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)
事实上 (<*>)
的任何定义都必须等同于 Monad
实例。
正如您正确注意到的那样,在这种情况下:
(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
。如果你有一些函数可以接受 l
和 mx
并创建一个 Expr b
。这样的函数,如果存在的话,可能会有签名:
someFunc :: Expr (a -> b) -> Expr a -> Expr b
当然,someFunc l mx
和someFunc r mx
都是Expr b
类型,只用一个就可惜了。如果有某种方法可以从两个 Expr b
部分 构建 一个 Expr b
,那真的是蜜蜂的膝盖。
您对 Val n
案例中可用的类型有轻微的误解。您没有 Expr a
,而是 Expr (a -> b)
,根本没有 a
或 b
(甚至 a -> b
中的函数也没有,因为 Val
只包含一个 Int
)。事实上,这种情况很简单 因为 你周围没有有用的值:你可能做的唯一合理的事情就是使用构造函数 Val
产生输出,因为你有无法凭空制造 b
。 Val
的类型可以专门化为 Val :: Int -> Expr b
,幸运的是,你有一个 Int
,所以你可以写:
(Val n) <*> mx = Val n