Reader monad - 它如何符合 Monad 接口?
Reader monad - how does it conform to Monad interface?
我正在学习范畴论。
我理解 reader monad 的概念,它甚至很容易实现:
case class Reader[DEP, A](g: DEP => A) {
def apply(dep: DEP): A = g(dep)
def map[B](f: A => B): Reader[DEP, B] = Reader(dep => f(apply(dep)))
def flatMap[B](f: A => Reader[DEP, B]): Reader[DEP, B] = Reader(dep => f(apply(dep)) apply dep)
}
但是,我在使用某些通用 Monad 接口的约束实现它时遇到问题,即
trait Monad[A] {
def pure(a: A): Monad[A]
def map[B](f: A => B): Monad[B]
def flatMap[B](f: A => Monad[B]): Monad[B]
}
让我们暂时忘记有一个 applicative 或 functor,让我们把这 3 个方法放在这里。
现在,有了这个接口,我在实现 ReaderMonad 时遇到了问题。
map 方法非常简单,但是 pure 和 flatMap 呢?
pure on Reader 甚至意味着什么?
要实现 flatMap,我需要一个从 A 到 Reader[DEP, B] 的函数,但我有 A => Monad[B],因此我无法访问 apply.
case class Reader[DEP, A](g: DEP => A) extends Monad[A] {
def apply(dep: DEP): A = g(dep)
override def pure(a: A): Reader[DEP, A] = Reader(_ => a) // what does it even mean in case of Reader
override def map[B](f: (A) => B): Reader[DEP, B] = Reader(dep => f(apply(dep)))
override def flatMap[B](f: (A) => Monad[B]): Reader[DEP, B] = ??? // to implement it, I need f to be (A) => Reader[DEP, B], not (A) => Monad[B]
}
在scala中可以这样实现吗?我尝试使用自绑定类型,但也没有用。
我知道像 scalaz 或 cats 这样的库使用类型类来实现这些类型,但这只是为了教育目的。
正如您在尝试实现 flatMap
时所发现的那样,声明 Monad
特性的问题是您在链接操作时丢失了正在定义的特定 monad 类型。定义 Monad
特征的通常方法是通过类型构造函数对其进行参数化,例如为
定义 monad 实例
trait Monad[M[_]] {
def pure[A](a: A): M[A]
def map[A, B](f: A => B, m: M[A]): M[B]
def flatMap[A, B](f: A => M[B], m : M[A]): M[B]
}
所以M
是一元类型的构造器,比如List
或者Option
。您可以将 Reader[DEP, A]
视为依赖于某种环境类型 DEP
的计算,其中 returns 是类型 A
的值。由于这有两个类型参数,因此您需要在定义 monad 实例时修复环境参数类型:
case class Reader[DEP, A](g: DEP => A)
class ReaderMonad[DEP]() extends Monad[({type t[X] = Reader[DEP, X]})#t] {
def pure[A](a: A) = Reader[DEP, A](_ => a)
def map[A, B](f: A => B,m: Reader[DEP,A]): Reader[DEP,B] = Reader(env => f(m.g(env)))
def flatMap[A, B](f: A => Reader[DEP,B],m: Reader[DEP,A]): Reader[DEP,B] = Reader(env => f(m.g(env)).g(env))
}
({type t[X] = Reader[DEP, X]})#t
是一个 type lambda,用于部分应用 Reader[DEP, A]
的两个参数之一。
现在pure
returns一个Reader
忽略环境和returns直接给定的值。
flatMap
构造一个 Reader
,当 运行 将 运行 内部计算时,使用结果构造下一个计算并 运行 它与同样的环境。
我正在学习范畴论。 我理解 reader monad 的概念,它甚至很容易实现:
case class Reader[DEP, A](g: DEP => A) {
def apply(dep: DEP): A = g(dep)
def map[B](f: A => B): Reader[DEP, B] = Reader(dep => f(apply(dep)))
def flatMap[B](f: A => Reader[DEP, B]): Reader[DEP, B] = Reader(dep => f(apply(dep)) apply dep)
}
但是,我在使用某些通用 Monad 接口的约束实现它时遇到问题,即
trait Monad[A] {
def pure(a: A): Monad[A]
def map[B](f: A => B): Monad[B]
def flatMap[B](f: A => Monad[B]): Monad[B]
}
让我们暂时忘记有一个 applicative 或 functor,让我们把这 3 个方法放在这里。
现在,有了这个接口,我在实现 ReaderMonad 时遇到了问题。 map 方法非常简单,但是 pure 和 flatMap 呢? pure on Reader 甚至意味着什么? 要实现 flatMap,我需要一个从 A 到 Reader[DEP, B] 的函数,但我有 A => Monad[B],因此我无法访问 apply.
case class Reader[DEP, A](g: DEP => A) extends Monad[A] {
def apply(dep: DEP): A = g(dep)
override def pure(a: A): Reader[DEP, A] = Reader(_ => a) // what does it even mean in case of Reader
override def map[B](f: (A) => B): Reader[DEP, B] = Reader(dep => f(apply(dep)))
override def flatMap[B](f: (A) => Monad[B]): Reader[DEP, B] = ??? // to implement it, I need f to be (A) => Reader[DEP, B], not (A) => Monad[B]
}
在scala中可以这样实现吗?我尝试使用自绑定类型,但也没有用。 我知道像 scalaz 或 cats 这样的库使用类型类来实现这些类型,但这只是为了教育目的。
正如您在尝试实现 flatMap
时所发现的那样,声明 Monad
特性的问题是您在链接操作时丢失了正在定义的特定 monad 类型。定义 Monad
特征的通常方法是通过类型构造函数对其进行参数化,例如为
trait Monad[M[_]] {
def pure[A](a: A): M[A]
def map[A, B](f: A => B, m: M[A]): M[B]
def flatMap[A, B](f: A => M[B], m : M[A]): M[B]
}
所以M
是一元类型的构造器,比如List
或者Option
。您可以将 Reader[DEP, A]
视为依赖于某种环境类型 DEP
的计算,其中 returns 是类型 A
的值。由于这有两个类型参数,因此您需要在定义 monad 实例时修复环境参数类型:
case class Reader[DEP, A](g: DEP => A)
class ReaderMonad[DEP]() extends Monad[({type t[X] = Reader[DEP, X]})#t] {
def pure[A](a: A) = Reader[DEP, A](_ => a)
def map[A, B](f: A => B,m: Reader[DEP,A]): Reader[DEP,B] = Reader(env => f(m.g(env)))
def flatMap[A, B](f: A => Reader[DEP,B],m: Reader[DEP,A]): Reader[DEP,B] = Reader(env => f(m.g(env)).g(env))
}
({type t[X] = Reader[DEP, X]})#t
是一个 type lambda,用于部分应用 Reader[DEP, A]
的两个参数之一。
现在pure
returns一个Reader
忽略环境和returns直接给定的值。
flatMap
构造一个 Reader
,当 运行 将 运行 内部计算时,使用结果构造下一个计算并 运行 它与同样的环境。