7

コードの出現の初日を解決するために初めてを使用しましたが、改善できるかどうか疑問に思っています。

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読みやすさを向上させるために理解を深めるために書く方法はありますか?
  3. Applicativein cat のインスタンスはありますSeqか (scalaz には存在しないことはわかっています)。?
  4. コードを改善するアイデアはありますか?
4

1 に答える 1

9
  1. catsは、scalaz 用語であるState[S, A]stack-safe のエイリアスとして定義されているため、非常に長いシーケンスでも stackoverflow なしで実行される を返します。StateT[Eval, S , A]StateT[Trampoline, S, A]runSEval[A]valueflatMap
  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います。路地猫プロジェクトにはいくつかの非正統的なインスタンスがあります。が必要なのか、コードから が必要なのか、それともを に置き換えたのかはよくわかりません。路地猫に良いニュースがあります。たとえば、似たようなものを定義する私の試みは次のとおりですApplicative[Seq]Traverse[Seq]sequencesequence_Foldable[Seq]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
    
于 2016-12-31T15:49:28.410 に答える