I've used cats for the first time to solve day 1 of advent of code and I'm wondering if it's possible to improve things.
Given a method update
with the following signature
def update(i: Instruction): PosAndDir => PosAndDir
I've come up with :
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
And also
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
More precisely, questions are :
- why do we need to call
.value
(with scalaz, it's transparent) ? - is there a way to write
update2
with a for comprehension to improve readability ? - is there an
Applicative
instance forSeq
in cats (I know there is not in scalaz). ? - any idea to improve the code ?
State[S, A]
as an alias for stack-safeStateT[Eval, S , A]
which isStateT[Trampoline, S, A]
in scalaz terms, sorunS
returnsEval[A]
, wherevalue
will be run without stackoverflow even for very longflatMap
sequences.Using some more additional imports
and some preparations
you can make your function look like this
not that this solution will not work in 2.12 due to this improvement, you can make it work with this workaround
There is no instances for
Seq
, this answer describes why. While there are some non-orthodox instances in the alleycats project. I'm not really sure if you need forApplicative[Seq]
, from your code you are rather have need forTraverse[Seq]
, or if you replace yoursequence
withsequence_
evenFoldable[Seq]
. Good news there isFoldable[Iterable]
in the alleycats, and here is my attempt to define something lookalike forSeq
instancedidn't spent much time but here is my attempt to simplifying some parts via the Monocle library: