(->)当我查阅有关(->)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. Monad和Functor类型都有类型* -> *,所以他们只期望一个类型参数.
这意味着是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 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)
Run Code Online (Sandbox Code Playgroud)
这样做是将隐式参数应用于f绑定右侧的每个函数.所以,如果你在传递1.0给f,它将值绑定2 * 1.0到x1并结合2 + 1.0到x2,然后返回(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变换器,允许您将其构建到变换器堆栈中,让您拥有非常复杂的应用程序,可以轻松访问静态配置.
我认为如果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)
| 归档时间: |
|
| 查看次数: |
271 次 |
| 最近记录: |