In this session SystemFw gives an example of implementing State[S, A]
wih vanilla scala, When follow the exmple, I run into a trouble in supplying a Applicative definition for the vanilla State type (In order to get the commands.traverse
work. See code here
I tried to make a implicit def to solve the Applicative instance, but didn't figure out how to deal with the 2 type parameter.
How to implement Applicative for this type:
case class State[S, A](modify: S => (A, S)) {
def runA(initial: S): A = modify(initial)._1
def flatMap[B](f: A => State[S, B]): State[S, B] =
State { s =>
val (result, nextState) = modify(s)
f(result).modify(nextState)
}
}
Wrong code:
implicit def stateApplicative[S, A]: Applicative[State[S, A]] = new Applicative[State[S, A]] {
override def pure[A](x: A): State[A???] = ??? // error
override def ap[A, B](ff: State[A => B])(fa: State[A???]): State[B] = ??? // error
}
Basically, the solution to this problem is always fixing one type parameter.
In the case of a State you want the value inside the state to change but no the type of the state itself so you fix S
.
So you can create an application for a given particular state, for example Int
type IntState[A] = State[A, Int]
implicit final val intStateApplicative: Applicative[IntState] =
new Applicative[IntState] {
// Some implementation.
}
However, after you fill the implementation you will see that the fact of knowing that S
was Int
was meaningless. And that we could just copy and paste the whole code if S
would have been String
or whatever.
So, what we want is a way to say that this works for any S
, we can do that with a type lambda (ie a function in the type level) .
type StateTypeFun[S] = { type F[A] = State[A, S] }
implicit final def stateApplicative[S]: Applicative[StateTypeFun[S]#F] =
new Applicative[StateTypeFun[S]#F] {
// Some implementation.
}
And that is how we solve this problem.
Note that the type alias is unnecessary but makes the code easier to read, but you could have done Applicative[({ type F[A] = State[A, S]})#F]
.
BTW, because this necessity of creating type lambdas is somewhat common in Scala 2 we have kind projector , and Scala 3 has proper syntax support for it.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.