I am learning monad transformers and have a problem sequencing them
I created a type OptionTBitSetState[T]
I understand this type as a stateful computation that may fail
import scalaz._, Scalaz._
import scala.collection.immutable.BitSet
type BitSetState[T] = State[BitSet, T]
type OptionTBitSetState[T] = OptionT[BitSetState, T]
object OptionTBitSetState {
def apply[T](option : Option[T]) : OptionT[BitSetState, T] =
OptionT[BitSetState, T](State[BitSet, Option[T]](_ -> option))
def apply[T](state : State[BitSet, T]) : OptionT[BitSetState, T] =
OptionT[BitSetState, T](state.map(_.some))
}
I have a function step with signature
def step(i : Int) : OptionTBitSetState[Seq[Int]]
This function should:
- Check if BitSet inside State contains parameter
i
- If it does not contain: add
i
to BitSet and returnSeq(i, i*10, i*100)
- If it contains: fail with
None
- If it does not contain: add
Implementation of function step:
def step(i : Int) : OptionTBitSetState[Seq[Int]] =
for {
usedIs <- OptionTBitSetState(get[BitSet])
res <- OptionTBitSetState(
Some(Seq(i, i*10, i*100)).filterNot(_ => usedIs.contains(i))
)
_ <- OptionTBitSetState(put(usedIs + i))
} yield res
I want to sequence a list of steps in such way that when I evaluate this sequence, I get a list of options as a result. But signature of sequence
is different. I get an option of lists instead.
e.g.
List(1,2,1,3).map(step).sequence.run(BitSet.empty)
returns None
, but what I want is:
List(Some(Seq(1, 10, 100)), Some(Seq(2, 20, 200)), None, Some(Seq(3, 30, 300)))
Is there any way I can combine OptionTBitSetState[T]
s, so I will get the behavior I need?
In my humble opinion, you are over-complicating the solution by using
OptionT
.The problem with
OptionT
is that it wants to treat the value inside the monad as either existing or absent, so when you 'collapse' the individual computations into a single State to run it, any single failure must cause the entire thing to fail.I would just use
State[BitSet,Option[Seq[Int]]
. Here's a (slightly modified for simplicity) Haskell version since I don't speak Scala particularly well.What you really want is
mapM
or whatever Scala's equivalent is. Then just run the State action and remove the Nothing values.