繁体   English   中英

如何使用猫和状态Monad

[英]How to use cats and State Monad

我第一次使用来解决代码出现的第一 ,我想知道是否有可能改进。

给定具有以下签名def update(i: Instruction): PosAndDir => PosAndDir的方法update def update(i: Instruction): PosAndDir => PosAndDir

我想出来:

val state: State[PosAndDir, List[Unit]] = instructions.map(i => State.modify(update(i))).toList.sequenceU
val finalState = state.runS(PosAndDir(Pos(0, 0), North)).value

并且

  def update2(i: Instruction): State[PosAndDir, Option[Pos]] =
    State.modify(update(i)).inspect(pad => if (i == Walk) Some(pad.pos) else None)
  …
  val state = instructions.map(update2).toList.sequenceU
  val positions = state.runA(PosAndDir(Pos(0, 0), North)).value.flatten

更确切地说,问题是:

  1. 为什么我们需要调用.value (使用scalaz,它是透明的)?
  2. 有没有办法写一个update2与for comprehension提高可读性?
  3. 是否有Applicative于猫的Seq实例(我知道scalaz中没有)。
  4. 任何改进代码的想法?
  1. cats将State[S, A]定义为堆栈安全StateT[Eval, S , A]的别名,它是StateT[Trampoline, S, A] ,因此runS返回Eval[A] ,其中value将运行即使对于很长的flatMap序列,也没有stackoverflow。
  2. 使用一些额外的进口

     import cats.data.{State, StateT} import cats.MonadState import cats.syntax.functorFilter._ import cats.instances.option._ 

    和一些准备工作

     type Walk[x] = StateT[Option, PosAndDir, x] val stateMonad = MonadState[Walk, PosAndDir] import stateMonad._ 

    你可以让你的功能看起来像这样

     def update2(i: Instruction): StateT[Option, PosAndDir, Pos] = for (pad ← get if i == Walk) yield pad.pos 

    并不是说这个解决方案在2.12中不起作用,因为这种改进 ,你可以使它适用于这种解决方法

     implicit class FunctorWithFilter[F[_] : FunctorFilter, A](fa: F[A]) { def withFilter(f: A ⇒ Boolean) = fa.filter(f) } 
  3. Seq没有实例, 这个答案描述了原因。 虽然alleycats项目中有一些非正统的例子。 我不确定你是否需要Applicative[Seq] ,从你的代码中你需要Traverse[Seq] ,或者你用sequence替换你的sequence_甚至Foldable[Seq] alleycats中Foldable[Iterable]好消息,这是我尝试为Seq实例定义类似的东西

     implicit val seqInstance = new MonadFilter[Seq] with Traverse[Seq] { def traverse[G[_] : Applicative, A, B](fa: Seq[A])(f: (A) ⇒ G[B]): G[Seq[B]] = fa match { case head +: tail ⇒ f(head).map2(traverse(tail)(f))(_ +: _) case _empty ⇒ Seq.empty[B].pure[G] } def foldLeft[A, B](fa: Seq[A], b: B)(f: (B, A) ⇒ B): B = fa.foldLeft(b)(f) def foldRight[A, B](fa: Seq[A], lb: Eval[B])(f: (A, Eval[B]) ⇒ Eval[B]): Eval[B] = fa match { case head +: tail ⇒ f(head, foldRight(tail, lb)(f)) case _empty ⇒ lb } def pure[A](x: A): Seq[A] = Seq(x) def empty[A]: Seq[A] = Seq.empty[A] def flatMap[A, B](fa: Seq[A])(f: (A) ⇒ Seq[B]): Seq[B] = fa.flatMap(f) def tailRecM[A, B](a: A)(f: (A) ⇒ Seq[Either[A, B]]): Seq[B] = { @tailrec def go(seq: Seq[Either[A, B]]): Seq[B] = if (seq.contains((_: Either[A, B]).isLeft)) go(seq.flatMap { case Left(a) ⇒ f(a) case b ⇒ Seq(b) }) else seq.collect { case Right(b) ⇒ b } go(Seq(Left(a))) } override def mapFilter[A, B](fa: Seq[A])(f: (A) ⇒ Option[B]): Seq[B] = fa.flatMap(f(_).toSeq) } 
  4. 并没有花太多时间,但这是我试图通过Monocle库简化一些部分:

     import cats.{MonadState, Foldable, Functor} import cats.instances.option._ import cats.syntax.foldable._ import cats.syntax.functor._ import cats.syntax.functorFilter._ import monocle.macros.Lenses @Lenses case class Pos(x: Int, y: Int) sealed abstract class Dir(val cmd: Pos ⇒ Pos) case object South extends Dir(Pos.y.modify(_ - 1)) case object North extends Dir(Pos.y.modify(_ + 1)) case object East extends Dir(Pos.x.modify(_ + 1)) case object West extends Dir(Pos.x.modify(_ - 1)) @Lenses case class PosAndDir(pos: Pos, dir: Dir) val clockwise = Vector(North, East, South, West) val right: Map[Dir, Dir] = clockwise.zip(clockwise.tail :+ clockwise.head).toMap val left: Map[Dir, Dir] = right.map(_.swap) sealed abstract class Instruction(val cmd: PosAndDir ⇒ PosAndDir) case object TurnLeft extends Instruction(PosAndDir.dir.modify(left)) case object TurnRight extends Instruction(PosAndDir.dir.modify(right)) case object Walk extends Instruction(pd ⇒ PosAndDir.pos.modify(pd.dir.cmd)(pd)) def runInstructions[F[_] : Foldable : Functor](instructions: F[Instruction])(start: PosAndDir): PosAndDir = instructions.map(i => State.modify(i.cmd)).sequence_.runS(start).value 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM