Found: (MyTracker.this.mystate : A) Required: MyTracker.B

I have trait for state transition purpose defined like

// A --(transit)--> B --(transit)--> C for instance
sealed trait MyState
case object A extends MyState
final case class B(value: Option[Long] = None) extends MyState
case object C extends MyState

Now I have a case class that holds this state and cats.data.IndextedStateT for performing state transition. But an error Found: (MyTracker.this.mystate : A) Required: MyTracker.B is thrown. The workflow on my mind is something like val mytracker1: MyTracker[B] = create(); val mytracker2: MyTracker[C.type] = mytracker1.nextState(). But apparently mystate in the nextState() function is treated as type parameter A, even though it’s a sub type of MyState that can also be MyState.A or MyState.C. How can I refactor so that I do not need to cast type e.g. state2.runS(mystate.asInstanceOf[B]).value? Thanks

MyTracker {
    sealed trait MyState
    case object A extends MyState
    final case class B(value: Option[Long] = None) extends MyState
    case object C extends MyState

    def create(): MyTracker[B] = {
        val state1: IndexedStateT[Eval, Unit, B, Unit] = IndexedStateT.set(B())
        Server(state1.runS(()).value)
    }
}
case class MyTracker[+A <: MyTracker.MyState](mystate: A) {
    def nextState(): MyTracker[C.type] = {
        val state2: IndexedStateT[Eval, B, C.type, Unit] = IndexedStateT.set(C)
        Server(state2.runS(mystate).value) // <--- "mystate" is highlighted with red line
    }
}

You have an indexed state transformer state2 for a transition from a B to the C, but you are running it on an arbitrary state that could be an A,B or C. So how could this possibly work, even with a runtime type coercion?

If you really want to take an arbitrary state and apply some transition to it using a state transformer, why not do a pattern match in nextState and build the right kind of state2 in each case of the match?

As rhetorical question to ponder offline: why use a state transformer when there is no monadic calculation flow? I would just have the pattern match cases construct the following state directly.

I might move nextState into MyState and decentralise the transition logic as overrides, or stick with a pattern match and sack MyTracker.

Just out of curiosity, was this written by an LLM? Not singling you out specifically, I’m going to start asking this more often…

EDIT: I mean of course, was the code example written by an LLM. Then again, given some of the posts I’m seeing these days here and there, I wonder…

1 Like

Thanks for the advice.

Don’t know why you think the code coming from LLM. I am very happy that I am the old style person who dislike asking OpenAI or alike to provide code for me.

I borrowed the code from Typelevel doc State. Then I changed the code to fit my requirement that I do not want to copy unrelated part here. Therefore, I updated some var names, and remove unrelated code.

Anyway, thanks again for the reply. Appreciate it.

1 Like

I’m glad that you turned out to be old-school!

I did get a sense that the code was based on the typelevel documentation, which made me wonder whether an LLM had been trained on it and was regurgitating it, hence my question.

Where I’m coming from on this, btw, is 1) genuinely wondering just how good are LLMs these days at code generation, 2) my profound distaste for possibly spending my time correcting code produced by people who couldn’t be asked to invest their own time in getting the skills to write that code to start with and 3) my aversion to being used to train said LLMs. Teaching or helping people to fish is a rewarding experience, buying fish for strangers less so. :cat_with_wry_smile: