当我在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?
答案 0 :(得分:13)
一开始可能有点令人困惑,但要记住的一个重要概念是(->)
不是monad或functor,但(->) r
是。{1}}。 Monad
和Functor
类型都具有* -> *
类型,因此它们只需要一个类型参数。
这意味着fmap
的{{1}}看起来像
(->) r
这也称为
fmap g func = \x -> g (func x)
这只是正常的功能构成!当您fmap g func = g . func
超过fmap g
时,您可以通过对其应用func
来更改输出类型。在这种情况下,如果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
,然后返回{ {1}}。它确实可以很容易地将单个参数应用于许多子表达式。此功能相当于
x2
为什么这有用?一个常见的用途是(x1, x2)
monad,它只是f' x = (2 * x, 2 + x)
周围的新类型包装器。 Reader
monad使您可以轻松地在应用程序中应用静态全局配置。你可以编写像
(->) r
然后使用Reader
运行您的应用程序。您可以轻松地在myApp :: Reader Config ()
myApp = do
config <- ask
-- Use config here
return ()
monad中编写操作,编写它们,将它们链接在一起,并且所有这些操作都可以访问全局的readonly配置。此外,还有一个伴随runReader myApp initialConfig
monad转换器,允许您将其构建到变换器堆栈中,让您拥有非常复杂的应用程序,可以轻松访问静态配置。
答案 1 :(得分:5)
如果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
答案 2 :(得分:1)
您可以查看自己,例如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