简体   繁体   English

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

[英]Intrigued by (->) as instances of monad and functor

I am quite intrigued by (->) when I looked up in information about (->) in ghci. 当我在ghci中查找(->)信息时,我对(->)非常感兴趣。 It says, 它说,

data (->) a b -- Defined in `GHC.Prim`

So far so good, but then it gets very interesting when it says - 到目前为止一切都那么好,但是当它说 - 时它变得非常有趣 -

instance Monad ((->) r) -- Defined in `GHC.Base`
instance Functor ((->) r) -- Defined in `GHC.Base`

What does this implicate? 这意味着什么? Why does GHC define it as an instance of a Monad, and Functor for (->) ? 为什么GHC将它定义为Monad的实例,以及(->) Functor?

It can be a bit confusing at first, but one important concept to remember is that (->) is not a monad or functor, but (->) r is. 起初可能有点令人困惑,但要记住的一个重要概念是(->)不是monad或functor,但是(->) r是。 Monad and Functor types all have the kind * -> * , so they only expect one type parameter. MonadFunctor类型都有类型* -> * ,因此它们只需要一个类型参数。

What this means is that fmap for (->) r looks like 这意味着(->) r fmap看起来像

fmap g func = \x -> g (func x)

Which is also known as 这也被称为

fmap g func = g . func

which is just normal function composition! 这只是正常的功能构成! When you fmap g over func , you change the output type by applying g to it. 当您通过func fmap g时,可以通过对其应用g来更改输出类型 In this case, if func has the type a -> b , g must have a type like b -> c . 在这种情况下,如果func的类型为a -> b ,则g必须具有类似b -> c的类型。

The Monad instance is bit more interesting. Monad实例更有趣。 It lets you use the result of a function application "before" that application has occurred. 它允许您在应用程序“之前”使用函数应用程序的结果。 What helped me understand was seeing an example like 帮助我理解的是看到一个例子

f :: Double -> (Double,Double)
f = do
    x1 <- (2*)
    x2 <- (2+)
    return (x1, x2)

> f 1.0
(2.0, 3.0)

What this does is apply the implicit argument to f to each of the functions on the right hand side of the binds. 这样做是将f的隐式参数应用于绑定右侧的每个函数。 So if you pass in 1.0 to f , it will bind the value 2 * 1.0 to x1 and binds 2 + 1.0 to x2 , then returns (x1, x2) . 因此,如果将1.0传递给f ,它会将值2 * 1.0绑定到x1并将2 + 1.0绑定到x2 ,然后返回(x1, x2) It really makes it easy to apply a single argument to many subexpressions. 它确实可以很容易地将单个参数应用于许多子表达式。 This function is equivalent to 这个功能相当于

f' x = (2 * x, 2 + x)

Why is this useful? 为什么这有用? One common use is the Reader monad, which is simply a newtype wrapper around (->) r . 一个常见的用途是Reader monad,它只是一个围绕(->) r的newtype包装器。 The Reader monad makes it easy to apply a static global config across your application. Reader monad使您可以轻松地在应用程序中应用静态全局配置。 You could write code like 你可以写代码

myApp :: Reader Config ()
myApp = do
    config <- ask
    -- Use config here
    return ()

And then you run your application with runReader myApp initialConfig . 然后使用runReader myApp initialConfig运行应用程序。 You can easily write actions in the Reader Config monad, compose them, chain them together, and all of them have access to the global, readonly config. 您可以轻松地在Reader Config monad中编写操作,组合它们,将它们链接在一起,并且所有这些操作都可以访问全局的readonly配置。 In addition, there's a companion ReaderT monad transformer which allows you to build it into your transformer stack, letting you have very complex applications that have easy access to static configuration. 此外,还有一个配套的ReaderT monad变换器,允许您将其构建到变换器堆栈中,让您拥有非常复杂的应用程序,可以轻松访问静态配置。

I think it would be a bit less confusing if Haskell had just always allowed type operator sections: 我认为如果Haskell总是允许类型操作符部分,那会有点混乱:

data a->b

instance Monad (r -> )

looks much more natural. 看起来更自然。

For short explanation: I find it quite helpful to consider the special case Monad (Bool -> ) , which is basically a two-element container type. 简而言之:我发现考虑特殊情况Monad (Bool -> )非常有帮助,它基本上是一个双元素容器类型。 It has the two elements 它有两个要素

\case
  False -> elem1
  True -> elem2

So you can think about the functor instance much the same as for lists: map over "all contained elements". 因此,您可以考虑与列表相同的仿函数实例:映射“所有包含的元素”。

The applicative and monad instances are a bit different, it might help to make the "container transformation" explicit: 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

You can check yourself, for example at http://hackage.haskell.org/package/base-4.6.0.1/docs/src/GHC-Base.html 您可以查看自己,例如http://hackage.haskell.org/package/base-4.6.0.1/docs/src/GHC-Base.html

Copied from there: 从那里复制:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM