解读《Simplicitly》中的`Reader` trait定义疑问
关于《Simplicitly》中Reader trait定义的疑问解答
在Odersky等人的《Simplicitly: foundations and applications of implicit function types》论文中,给出了如下Reader trait定义:
trait Reader[R, A] { def ask: R def local[A](f: R => R)(a: A): A }
针对你提出的四个问题,解答如下:
1. 该定义是否存在笔误?
肯定存在笔误:
local方法里的[A]直接遮蔽了外层trait的类型参数A,这是明显的低级错误,正常应该用一个全新的类型参数(比如B);- 外层
trait Reader[R, A]的A完全没被用到——ask直接返回R,local的参数和返回值也和这个A无关,这不符合标准Reader类型的设计逻辑,说明要么是简化过度,要么是遗漏了核心关联代码。
2. 若为笔误,我推测的成因是否合理?
如果你的推测方向是作者为了聚焦隐式函数类型的核心,刻意简化Reader定义,同时写代码时不小心重复用了A作为方法的类型参数,那这个推测完全合理:
- 这篇论文的核心是隐式函数类型,Reader只是用来辅助演示的工具,作者大概率不想被Monad/Effect这类额外的抽象层分散读者注意力,所以做了极端简化;
- 重复使用类型参数名是写示例代码时的常见失误,尤其是在快速编写演示代码的时候很容易犯这种错。
3. 是否有相关定义能帮助理解该定义?
可以对照几个标准的Reader相关定义来理清逻辑:
Haskell的MonadReader
Haskell里的MonadReader是最经典的Reader抽象,核心定义是:
class Monad m => MonadReader r m | m -> r where ask :: m r local :: (r -> r) -> m a -> m a
它定义了在Monad上下文m中读取环境r,以及修改环境后执行Monadic计算的能力。
Cats-MTL的Ask/Local
Scala的Cats-MTL把Reader的能力拆分成了两个类型类:
trait Ask[F[_], R] { def ask: F[R] } trait Local[F[_], R] extends Ask[F[_], R] { def local[A](f: R => R)(fa: F[A]): F[A] }
Ask负责读取环境,Local则负责局部修改环境后执行Effect计算F[A]。
无Effect层的基础Reader数据类型
如果不考虑Effect,最基础的Reader数据类型是这样的:
case class Reader[R, A](run: R => A) { def ask: Reader[R, R] = Reader(identity) def local[B](f: R => R)(reader: Reader[R, B]): Reader[R, B] = Reader(r => reader.run(f(r))) }
这里Reader[R,A]明确代表“输入R得到A”的计算,local的作用是修改输入环境后执行另一个Reader计算。
对比这些标准定义就能明白,论文里的版本是简化+笔误后的产物,它想表达Reader的核心能力,但遗漏了计算层的关联,还写错了类型参数。
4. 代码块前的「monad instance omitted」注释是否对应省略M[_]/F[_]的惯例?
没错,这个注释完全符合函数式编程示例代码的惯例:
- 当作者想聚焦某个抽象的核心逻辑(比如这里的环境读取和局部修改),而不想被Monad/Effect的
F[_]层分散注意力时,就会省略F[_]相关的Monad实例代码; - 论文里的完整定义本来应该带有
F[_](类似Cats-MTL的Local),但作者为了简化演示,把这一层省略了,用注释提示读者:完整定义需要结合Monad/Effect类型。
内容的提问来源于stack exchange,提问作者Andrey Tyukin
相关产品推荐
相关产品推荐

