我最近提出了一些问题,要求找到一种智能且易读的方法来解决这个更复杂的问题。
我需要一个带有此签名的超级组合器:
def runStateCombinator[T, E, A](t : T, readerFactories: Seq[T => Reader[E, State[A, Unit]]], f : E => A) : Reader[E, A] = {
别担心,这只是一个有状态的计算(State
)需要一些代表(Reader
)。
这是我目前的代码,任何改进都非常受欢迎(我是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)
}
答案 0 :(得分:1)
一般来说,monad变形金刚可能是一个救世主,但在如此小的一块中,它们只能创造出大量的样板,尤其是没有善良的投影仪。
更具体地说,您的transpose
只是sequence
的别名,Unapply
可能需要额外的Reader
您的map2
可以重构为简单的应用ap
另请注意,state.run(..)._1
已有别名exec
我添加了.toList
Seq
scalaz
总的来说,我的简化尝试是
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 trasformer可以进行整个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)
}