haskell - 如何阅读 MonadReader 并询问定义?
问题描述
我想弄清楚如何阅读以下类类型定义:
Prelude Data.Functor.Identity Control.Monad.Reader> :i ask
class Monad m => MonadReader r (m :: * -> *) | m -> r where
ask :: m r
...
m
是更高种类的类型,它必须是monad
.
但 是什么m -> r
意思?
尝试玩一下ask
如下:
Prelude Data.Functor.Identity Control.Monad.Reader> ask "Hello"
"Hello"
为什么我可以将参数传递给ask
?查看类型签名:
ask :: m r
我无法识别,我可以将参数传递给ask
.
解决方案
是m -> r
一个函数依赖,它粗略地指出,当尝试选择MonadReader
要使用的实例时,知道m
就足够了r
。换句话说,您不能定义两个具有相同m
但不同的单独实例r
。
现在,为了确定ask
使用哪个定义,我们转向类型推断。根据它的定义,我们知道ask
有 type MonadReader r m => m r
。从它在 中的使用ask "Hello"
,我们知道它也必须有一个像a -> b
; 更具体地说,我们知道 与a
统一String
,因为那是 的类型"Hello"
。MonadReader r m => m r
所以我们的任务是与统一String -> b
。
这很简单。用前缀符号重写String -> b
并使用显式括号,我们可以将它们排列在一起:
MonadReader r m => m r
((->) String) b
所以m ~ ((->) String)
和r ~ b
(尽管我们仍然不知道r/b
应该是什么)。查看 的可用实例MonadReader
,我们找到m ~ (->) String
(或更一般地说,(->) r
)的(唯一)实例:
instance MonadReader r ((->) r) where
ask = id
local f m = m . f
所以现在我们知道,对于我们的选择m
, ask = id
。(这也让我们看到了这r ~ b ~ String
一点。)
所以,ask "Hello" == id "Hello" == "Hello"
。
请注意,ask
不一定必须是函数。它也可能是 type 的值Reader r a
,在这种情况下runReader
必须用于提取函数。
> :t runReader ask
runReader ask :: a -> a
> runReader ask "Hello"
"Hello"
它也可能是一个更复杂的单子,涉及ReaderT
:
> :t runReaderT ask
runReaderT ask :: Monad m => a -> m a
> runReaderT ask "Hello" :: Maybe String
Just "Hello"
> runReaderT ask "Hello" :: Either String String
Right "Hello"
推荐阅读
- python - 在 Jupyter 笔记本中的两个 df 显示之间添加空格
- python - subprocess.getstatusoutput('ls -l') 仅适用于 python shell?
- phpmyadmin - date_format time with ":" 产生警告
- filesystems - 使用文件系统 Oak 存储库
- c# - 如何管理最大连接、HttpClient、C#?
- java - Hashmap 条目不进入列
- python-3.x - 如何导出vpython图片
- angular - 在 FormArray 上为 required 和 minlength 设置 formvalidator
- deployment - 您可以使用 Helm 指定 pod 部署顺序吗?
- amazon-web-services - CloudWatch 仪表板:环境在进入已终止状态时无法启动