我正在尝试从Scala的Redux中制作类似于combineReducers
的东西,当时每个函数都控制着状态的一小部分,但是却找不到一种使它安全的优雅方法。到目前为止,我有这样的东西看起来一点也不好。
sealed trait Event
case class Create() extends Event
case class Save() extends Event
object Reducers {
type IntState = Int
type StringState = String
def intReducer(e: Event, state: IntState): IntState = ???
def stringReducer(e: Event, state: StringState): StringState = ???
def combineReducers[E, S1, S2](f: (E, S1) => S1, g: (E, S2) => S2): (E, (S1, S2)) => (S1, S2) = {
{ (e: E, states: (S1, S2)) => (f(e, states._1), g(e, states._2)) }
}
def combineReducers2[E, S1, S2, S3](f: (E, (S1, S2)) => (S1, S2), g: (E, S3) => S3): (E, (S1, S2, S3)) => (S1, S2, S3) = ???
}
无形记录似乎是一个很好的选择,尽管它是重类型编程的新手,但我无法弄清楚接下来应该如何处理(或者应该使用带有标记的HList函数?)。 )
def combineReducers(fTag: String, f: (E,A) => A, gTag: String, g: (E,B) => B): (E, HList1) => HList2 = {
{ (e: E, state: HList3) =>
(fTag ->> f(e, state(fTag)) :: (gTag ->> g(e, state(gTag)) :: HNil
}
}
答案 0 :(得分:1)
去那里,尝试找出正确的typeclass是很有趣的:D
import cats._
import cats.implicits._
sealed trait Event
case class Create() extends Event
case class Save() extends Event
type Reducer[A] = (Event, A) => A
val intReducer: Reducer[Int] = ???
val stringReducer: Reducer[String] = ???
val doubleReducer: Reducer[Double] = ???
implicit object ReducerIS extends InvariantSemigroupal[Reducer] {
override def product[A, B](fa: Reducer[A], fb: Reducer[B]): Reducer[(A, B)] =
(e: Event, ab:(A,B)) => (fa(e,ab._1), fb(e, ab._2))
override def imap[A, B](fa: Reducer[A])(f: A => B)(g: B => A): Reducer[B] = (e, b) => f(fa(e, g(b)))
}
val combined: Reducer[(Int, String, Double)] = (intReducer, stringReducer, doubleReducer).tupled
我对InvariantSemigroupal
的实现不是很干净,但是实际上类型会迫使您始终难以理解。
在猫中,.tupled
方法是隐式的,在我们的情况下,InvariantSemigroupal
需要隐式Reducer