考虑一下,你有Nel of states(Nel代表NonEmptyList,更短的事情), 并且你希望将状态组合到一个状态,使用一些函数 f ,用于状态的左侧部分和 g 为州的正确部分。
所以你想要这样的东西:
def foldStatesG[S, A](in: NonEmptyList[State[S, A]])(f: (A, A) => A)(g: (S, S) => S): State[S, A] = {
in.foldLeft1((s1, s2) => State(e => {
val ss1 = s1(e)
val ss2 = s2(e)
g(ss1._1, ss2._1) -> f(ss1._2, ss2._2)
}))
}
我确信,我正在发明自行车,这种事情已经存在,可能是以更一般的方式。但是,通过scalaz我没有找到或认出它。希望对此主题有任何帮助。
第二个问题,描述了我是如何解决这个问题的。我想做一个小模拟,当你有一个敌人(认为它只是一个双倍),以及可能击中他的所有可能的法术 Nel [Spell] 。所以基本上我想生成所有可能的序列。例如,如果Nel [Spell] =($,#),那么给予敌人E,进展看起来像
E -> (), then Nel(E -> $, E -> #), then Nel(E -> $$, E -> ##, E -> $#, E-> #$) etc.. (pseudo code)
没有太多细节,我需要这样的东西:
def combineS(variations: NonEmptyList[Spell]): State[NonEmptyList[(Enemy, List[Spell])], Boolean]
换句话说,你为它提供了所有可能的动作,它模拟了所有可能的状态。您可以将其视为一种决策树,它分支每一步。 因此我定义了如何进行一个咒语。
def combineS1(spell: Spell): State[(NonEmptyList[(Enemy, List[Spell])]), Boolean]
// some logic
问题是,我无法通过简单的遍历来实现它:
def combineS(variations: NonEmptyList[Spell]): State[NonEmptyList[(Enemy, List[Spell])], Boolean] = {
val x = variations traverse combine1 // State[Nel[..], Nel[Boolean]
x map { _.suml1(conjunction)}
}
因为在遍历中,Nels不会相互附加,而是被丢弃。 这就是我提出这个解决方案的原因:
def combineS(variations: NonEmptyList[Spell]): State[NonEmptyList[(Enemy, List[Spell])], AllDead] = {
val x: NonEmptyList[State[NonEmptyList[(Enemy, List[Spell])], Boolean]] = variations map combineS
foldStates(x)(_ && _)(append)
}
该代码实际上正在运行,但我觉得有一种方法可以遍历它,而无需额外的 foldState 。
进行此类模拟的其他功能方法是什么(至少在概念方面)。我可以简单地编写它,而不使用高级概念,但这个练习的目的正是为了学习高级的东西。 (可能这正是作家莫纳德?或者是Comonad的工作?)
另外,如果stackoverflow不是这类问题的最佳位置,请指出,应该询问这些问题的哪个位置?
答案 0 :(得分:2)
好吧,回答第一部分,如果我们在Scalaz已经有Biapplicative
类型类的替代宇宙中,我们可以按如下方式使用它:
def foldStatesG[S, A](states: NonEmptyList[State[S, A]], s: (S, S) ⇒ S, a: (A, A) ⇒ A): State[S, A] =
states.foldLeft1(IndexedStateT.indexedStateTBiapplicative[Id, S].bilift2(s, a))
但是我们不这样做,所以我们需要类似下面的内容(n.b.我没有确保这样做在法律上有所作为):
trait Biapplicative[F[_, _]] extends Bifunctor[F] {
def bipure[A, B](a: ⇒ A, b: ⇒ B): F[A, B]
def biapply[A, B, C, D](fab: ⇒ F[A, B])(f: ⇒ F[A ⇒ C, B ⇒ D]): F[C, D]
def bilift2[A, B, C, D, E, G](fab: (A, B) ⇒ C, fde: (D, E) ⇒ G): (F[A, D], F[B, E]) ⇒ F[C, G] =
(fad: F[A, D], fbe: F[B, E]) ⇒
biapply(fbe)(bimap[A, D, B ⇒ C, E ⇒ G](fad)(fab.curried, fde.curried))
}
object Biapplicative {
implicit def indexedStateTBiapplicative[F[_], S1](implicit F: Applicative[F]) =
new Biapplicative[IndexedStateT[F, S1, ?, ?]] {
def bipure[A, B](a: ⇒ A, b: ⇒ B) =
StateT.constantIndexedStateT(b)(a)
def biapply[A, B, C, D]
(fab: ⇒ IndexedStateT[F, S1, A, B])
(f: ⇒ IndexedStateT[F, S1, A ⇒ C, B ⇒ D]) =
new IndexedStateT[F, S1, C, D] {
def apply(initial: S1): F[(C, D)] =
F.ap(fab(initial))(F.map(f(initial)) {
case (a2c, b2d) ⇒ Bifunctor[Tuple2].bimap(_)(a2c, b2d)
})
}
}
}