我第一次使用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
更确切地说,问题是:
.value
(使用scalaz,它是透明的)?update2
以提高可读性?Applicative
个Seq
个实例(我知道scalaz中没有)。 ?答案 0 :(得分:8)
State[S, A]
定义为堆栈安全StateT[Eval, S , A]
的别名,其中StateT[Trampoline, S, A]
为scalaz术语,因此runS
返回Eval[A]
,其中{{1}即使对于非常长的value
序列,也将在没有stackoverflow的情况下运行。使用更多其他导入
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
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]
并没有花太多时间,但这是我尝试通过Monocle library简化部分内容:
Seq