如何使用猫和状态Monad

时间:2016-12-31 10:21:05

标签: scala functional-programming scala-cats

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

给定具有以下签名的方法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. 有没有办法用{for}来理解update2以提高可读性?
  3. 猫中有ApplicativeSeq个实例(我知道scalaz中没有)。 ?
  4. 改进代码的任何想法?

1 个答案:

答案 0 :(得分:8)

  1. cats将State[S, A]定义为堆栈安全StateT[Eval, S , A]的别名,其中StateT[Trampoline, S, A]为scalaz术语,因此runS返回Eval[A],其中{{1}即使对于非常长的value序列,也将在没有stackoverflow的情况下运行。
  2. 使用更多其他导入

    flatMap

    和一些准备工作

    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._
    

    由于此improvement,此解决方案无法在2.12中使用,您可以使用此解决方法

    def update2(i: Instruction): StateT[Option, PosAndDir, Pos] =
      for (pad ← get if i == Walk) yield pad.pos
    
  3. implicit class FunctorWithFilter[F[_] : FunctorFilter, A](fa: F[A]) { def withFilter(f: A ⇒ Boolean) = fa.filter(f) } 没有实例,this answer描述了原因。虽然alleycats项目中有一些非正统的例子。我不确定您是否需要Seq,从您的代码中您需要Applicative[Seq],或者将Traverse[Seq]替换为sequence偶数{{ 1}}。 好消息alleycats中有sequence_,这是我尝试为Foldable[Seq]实例定义类似的内容

    Foldable[Iterable]
  4. 并没有花太多时间,但这是我尝试通过Monocle library简化部分内容:

    Seq