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

Yog*_*kar 11 haskell

(->)当我查阅有关(->)ghci的信息时,我非常感兴趣.它说,

data (->) a b -- Defined in `GHC.Prim`
Run Code Online (Sandbox Code Playgroud)

到目前为止一切都那么好,但是当它说 - 时它变得非常有趣 -

instance Monad ((->) r) -- Defined in `GHC.Base`
instance Functor ((->) r) -- Defined in `GHC.Base`
Run Code Online (Sandbox Code Playgroud)

这意味着什么?为什么GHC将它定义为Monad和Functor的实例(->)

bhe*_*ilr 13

起初它可能有点令人困惑,但要记住的一个重要概念(->)是不是monad或functor,而是(->) r. MonadFunctor类型都有类型* -> *,所以他们只期望一个类型参数.

这意味着是fmap(->) r的样子

fmap g func = \x -> g (func x)
Run Code Online (Sandbox Code Playgroud)

这也被称为

fmap g func = g . func
Run Code Online (Sandbox Code Playgroud)

这只是正常的功能构成!当你fmap gfunc,你改变了输出类型应用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)
Run Code Online (Sandbox Code Playgroud)

这样做是将隐式参数应用于f绑定右侧的每个函数.所以,如果你在传递1.0f,它将值绑定2 * 1.0x1并结合2 + 1.0x2,然后返回(x1, x2).它确实可以很容易地将单个参数应用于许多子表达式.这个功能相当于

f' x = (2 * x, 2 + x)
Run Code Online (Sandbox Code Playgroud)

为什么这有用?一个常见的用途是Readermonad,它只是一个newtype包装器(->) r.该Reader单子可以很容易地在你的应用程序中应用静态全局配置.你可以写代码

myApp :: Reader Config ()
myApp = do
    config <- ask
    -- Use config here
    return ()
Run Code Online (Sandbox Code Playgroud)

然后你运行你的应用程序runReader myApp initialConfig.您可以轻松地在Reader Configmonad中编写操作,组合它们,将它们链接在一起,并且所有这些操作都可以访问全局的readonly配置.此外,还有一个配套的ReaderTmonad变换器,允许您将其构建到变换器堆栈中,让您拥有非常复杂的应用程序,可以轻松访问静态配置.

  • `f :: Double - > Double`应该是`f :: Double - >(Double,Double)` (2认同)
  • 我使用它的一个地方是定义"谓词组合子",如`(<||>)= liftM2(||)`.现在你可以轻松地构建组合谓词`isAlpha <||> isLetter <||>(=='c'):: Char - > Bool`是一个非常愚蠢的例子.对我来说,`满足$ isAlpha <||> isLetter <||>(=='c')`看起来好于'满足$\c - > isAlpha c || isLetter c || c =='c'`. (2认同)

lef*_*out 5

我认为如果Haskell总是允许类型操作符部分,那会有点混乱:

data a->b

instance Monad (r -> )
Run Code Online (Sandbox Code Playgroud)

看起来更自然.

简而言之:我发现考虑特殊情况非常有帮助Monad (Bool -> ),它基本上是一个双元素容器类型.它有两个要素

\case
  False -> elem1
  True -> elem2
Run Code Online (Sandbox Code Playgroud)

因此,您可以考虑与列表相同的仿函数实例:映射"所有包含的元素".

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
Run Code Online (Sandbox Code Playgroud)

  • 像往常一样,Edward Kmett有Haskell库来研究:[reprsentable-functors](http://hackage.haskell.org/package/representable-functors-3.2.0.2/docs/Data-Functor-Representable.html).直接来自Haddocks,"Haskell类型的可表示的endofunctors与读者monad是同构的,因此可以免费继承大量的属性." 忽略"endo"和"category"位,你就有了这个想法. (3认同)