![](/img/trans.png)
[英]Use cases for functor/applicative/monad instances for functions
[英]Intrigued by (->) as instances of monad and functor
当我在ghci中查找(->)
信息时,我对(->)
非常感兴趣。 它说,
data (->) a b -- Defined in `GHC.Prim`
到目前为止一切都那么好,但是当它说 - 时它变得非常有趣 -
instance Monad ((->) r) -- Defined in `GHC.Base`
instance Functor ((->) r) -- Defined in `GHC.Base`
这意味着什么? 为什么GHC将它定义为Monad的实例,以及(->)
Functor?
起初可能有点令人困惑,但要记住的一个重要概念是(->)
不是monad或functor,但是(->) r
是。 Monad
和Functor
类型都有类型* -> *
,因此它们只需要一个类型参数。
这意味着(->) r
fmap
看起来像
fmap g func = \x -> g (func x)
这也被称为
fmap g func = g . func
这只是正常的功能构成! 当您通过func
fmap g
时,可以通过对其应用g
来更改输出类型 。 在这种情况下,如果func
的类型为a -> b
,则g
必须具有类似b -> c
的类型。
Monad
实例更有趣。 它允许您在应用程序“之前”使用函数应用程序的结果。 帮助我理解的是看到一个例子
f :: Double -> (Double,Double)
f = do
x1 <- (2*)
x2 <- (2+)
return (x1, x2)
> f 1.0
(2.0, 3.0)
这样做是将f
的隐式参数应用于绑定右侧的每个函数。 因此,如果将1.0
传递给f
,它会将值2 * 1.0
绑定到x1
并将2 + 1.0
绑定到x2
,然后返回(x1, x2)
。 它确实可以很容易地将单个参数应用于许多子表达式。 这个功能相当于
f' x = (2 * x, 2 + x)
为什么这有用? 一个常见的用途是Reader
monad,它只是一个围绕(->) r
的newtype包装器。 Reader
monad使您可以轻松地在应用程序中应用静态全局配置。 你可以写代码
myApp :: Reader Config ()
myApp = do
config <- ask
-- Use config here
return ()
然后使用runReader myApp initialConfig
运行应用程序。 您可以轻松地在Reader Config
monad中编写操作,组合它们,将它们链接在一起,并且所有这些操作都可以访问全局的readonly配置。 此外,还有一个配套的ReaderT
monad变换器,允许您将其构建到变换器堆栈中,让您拥有非常复杂的应用程序,可以轻松访问静态配置。
我认为如果Haskell总是允许类型操作符部分,那会有点混乱:
data a->b
instance Monad (r -> )
看起来更自然。
简而言之:我发现考虑特殊情况Monad (Bool -> )
非常有帮助,它基本上是一个双元素容器类型。 它有两个要素
\case
False -> elem1
True -> elem2
因此,您可以考虑与列表相同的仿函数实例:映射“所有包含的元素”。
applicative和monad实例有点不同,它可能有助于使“容器转换”显式:
data Pair a = Pair a a
instance Functor Pair where
fmap f (Pair a b) = Pair (f a) (f b)
instance Monad Pair where
return a = Pair a a
join (Pair (Pair a _) (Pair _ b))
= Pair a b
您可以查看自己,例如http://hackage.haskell.org/package/base-4.6.0.1/docs/src/GHC-Base.html
从那里复制:
instance Functor ((->) r) where
fmap = (.)
instance Monad ((->) r) where
return = const
f >>= k = \ r -> k (f r) r
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.