Seq[T => Reader[E, State[A, Unit]]] 到 Reader[E, A]

Seq[T => Reader[E, State[A, Unit]]] into Reader[E, A]

我最近问了一些问题,以找到一种聪明且可读的方法来解决这个更复杂的问题。

我需要一个带有这个签名的超级组合器:

def runStateCombinator[T, E, A](t : T, readerFactories: Seq[T => Reader[E, State[A, Unit]]], f : E => A) : Reader[E, A] = {

别担心,这只是一个需要一些依赖 (Reader) 的状态计算 (State)。

这是我当前的代码,欢迎任何改进(我是 scalaz n00b)。

  def runStateCombinator[T, E, A](t : T, readerFactories: Seq[T => Reader[E, State[A, Unit]]], f : E => A) : Reader[E, A] = {
    def transpose[E, A](readers : Seq[Reader[E, A]]) : Reader[E, Seq[A]] =
      Reader { e: E => readers.map { r => r(e) } }

    def map2[E, A, B](reader: Reader[E, A])(f: (E, A) => B) : Reader[E, B] =
      Reader { e => f(e, reader(e)) }

    val readers = readerFactories.map(_.apply(t))
    val stateReader = Readers.transpose(readers).map(_.sequenceS_[A, Unit])
    Readers.map2(stateReader)((ctx, state) => state.run(f(ctx))._1)
  }

一般来说,monad transformers 可能是一个救世主,但在这么小的部分中,它们只能创建很多样板,尤其是在没有 kind-projector 的情况下。

更具体地说,您的 transpose 只是 sequence 的别名,在 Reader 的情况下可能需要额外的 Unapply 您的 map2 可以重构为简单的应用程序 ap 另请注意,state.run(..)._1 已经有别名 exec

我还添加了额外的 .toList,因为 Seqscalaz

中没有很好地表示

总的来说,我的简化尝试是

import scalaz._
import scalaz.syntax.traverse._
import scalaz.std.list._
import syntax.monad._
import Id.Id

type ReadState[E, A, F[_]] = Reader[E, F[State[A, Unit]]]

def runStateCombinator[T, E, A](t: T, readerFactories: Seq[T => ReadState[E, A, Id]], f: E => A): Reader[E, A] = {
  val readers: ReadState[E, A, List] = readerFactories.map(_ (t)).toList.sequenceU
  val stateReader = readers.map(_.sequenceS_[A, Unit])
  stateReader <*> Reader(ctx => _.exec(f(ctx)))
}

例如,monad transformer 可以进行整个sequenceU.map(_.sequenceS_单一操作而不需要明确的结果类型。

另一种选择是使用可怕的 ReaderWriterState 进行空写入:

import scalaz._
import scalaz.syntax.traverse._
import scalaz.std.list._
import Id.Id
import ReaderWriterStateT._
import scalaz.std.anyVal._

type ReadState[E, A, X] = ReaderWriterState[E, Unit, A, X]

def runStateCombinator[T, E, A](t: T, readerFactories: Seq[T => ReadState[E, A, Unit]], f: E => A): Reader[E, A] = {
  val readers = readerFactories.map(_ (t)).toList
  val stateReader = readers.sequence_[ReadState[E, A, ?], Unit](implicitly, rwstMonad[Id, E, Unit, A])
  Reader(x => stateReader.exec(x, f(x))._2)
}