Typeclassopedia介绍了这个练习:
为(( - >)e)实现Monad实例。
这是MyMonad
类。
class (MyMonad m) where
ret :: a -> m a
flatMap :: m a -> (a -> m b) -> m b
然后,我开始尝试为((->) e)
实现Monad实例。
instance (MyMonad (-> e)) where
ret x = ...
flatMap m f = ...
但是,我对((->) e)
的含义没有直觉。
请帮助我理解它,并给我一个解决ret
的暗示。
答案 0 :(得分:6)
这里有一些语法技巧。可能更容易将(->) e
视为(e ->)
,或者更清楚地说,如果我们写
type Arr a b = a -> b
然后(->) e
与Arr e
大致相同。
那么ret
的类型是什么?它最终成为
ret :: a -> (e -> a)
现在应该更容易解决。
答案 1 :(得分:5)
如果Haskell允许类型操作符,这将更容易理解 各部门,IMO。类型
a -> b
相当于
(->) a b
这意味着
(->) a
与
相同(a ->)
它实质上是说它是参数化的函数类型 输出类型。所以这意味着我们应该
ret :: a -> (((->) r) a)
或等效
ret :: a -> ((r ->) a) -- Note that this is invalid Haskell, it's using our magical TypeOperatorSections extension
ret :: a -> (r -> a)
ret :: a -> r -> a
嗯,这种类型看起来非常简单和熟悉。如果我们在Hoogle上查找,那么 第一个结果是
const :: a -> b -> a
其余结果大约为seq
,par
,其他更高级
我们可以相当肯定的功能并不是我们正在寻找的东西。所以
const
它是:
instance MyMonad ((->) r) where
return = const
对于flatMap
的实现,我们可以从注释我们的参数开始
与他们的类型:
flatMap (m :: r -> a) (f :: a -> (r -> b)) = _
所以我们有一个函数,当给定r
时返回a
,以及一个函数
给定a
和r
返回b
,我们想要flatMap m f :: r -> b
。因为我们
没有r
类型的参数,让我们介绍一个:
flatMap m f = \r -> _
如果您正在使用打字孔,GHC现在会告诉您需要一些东西
输入b
。相关的绑定是
m :: r -> a
f :: a -> r -> b
r :: r
只有一种方法可以获得a
,m
来自flatMap m f = \r -> _ (m r)
,所以
a -> b
现在我们有GHC告诉我们,我们需要f :: a -> r -> b
r :: r
类型的相关信息
绑定
flatMap m f = \r -> f (m r) r
这对我来说非常简单:
test :: Int -> Int
test =
(*2) `flatMap` (\x1 ->
(^3) `flatMap` (\x2 ->
(7-) `flatMap` (\x3 ->
return (x1 * x2 + x3)
)
)
)
我们的代码类型检查!现在是时候测试一下了。期望的行为是
我们将相同的输入参数传递给do块中的几个函数(你
可以使用RebindableSyntax
如果你真的想用do notation),那就像
test' x = (2*x) * (x^3) + (7-x)
应与
相同> test 5 == test' 5
True
> test 100 == test' 100
True
对于我们的实施,它确实有效:
{{1}}