感兴趣的是( - >)作为monad和functor的实例

时间:2014-01-09 16:38:21

标签: haskell

当我在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?

3 个答案:

答案 0 :(得分:13)

一开始可能有点令人困惑,但要记住的一个重要概念是(->)不是monad或functor,但(->) r是。{1}}。 MonadFunctor类型都具有* -> *类型,因此它们只需要一个类型参数。

这意味着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