Reader monad - 它如何符合Monad界面?

时间:2017-02-05 17:55:58

标签: scala monads category-theory reader-monad

我正在学习类别理论。 我理解读者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]
}

让我们忘记一下,有一个应用程序或仿函数,让我们把这三种方法放在这里。

现在,有了这个界面,我在实现ReaderMonad时遇到了问题。 map方法非常简单,但是pure和flatMap呢? 在读者身上拥有纯粹的东西甚至意味着什么? 要实现flatMap,我需要有一个从A到Reader [DEP,B]的函数,但我有A => Monad [B],因此我无法访问申请。

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或cat这样的库使用类型类来实现这些类型,但这只是出于教育目的。

1 个答案:

答案 0 :(得分:2)

正如您在尝试实现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是一元型构造函数,例如ListOption。您可以将Reader[DEP, A]视为一种计算,它取决于某些环境类型DEP,它返回类型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]})#ttype lambda,用于部分应用Reader[DEP, A]的两个参数之一。

现在pure返回Reader,忽略环境并直接返回给定值。

flatMap构造一个Reader,当运行时将运行内部计算,使用结果构造下一个计算并使用相同的环境运行它。