0

overview

I'm trying to infer types of cats.data.IndexedStateT[F[_], SA, SB, A] passed in to the flatMap method. When just using flatMap, type inference seem to infer the type parameters for SA, SB and A correctly. However, when I use map within the flatMap it fails.

Is there a way to make this type inference work without manually specifying the type parameters for IndexedStateT passed into flatMap?

class X
class Y


// Type inference works well when just using flatMap
val res1: IndexedStateT[Eval, Unit, Y, Y] =
    IndexedStateT[Eval, Unit, X, X](_ => Eval.now(new X, new X))
      .flatMap { x =>
        IndexedStateT(_ => Eval.now(new Y, new Y)) // Infers IndexedStateT[Eval, X, Y, Y]
      }


// Type inference fails when mapping inside flatMap
val res2: IndexedStateT[Eval, Unit, Y, (X, Y)] =
    IndexedStateT[Eval, Unit, X, X](_ => Eval.now(new X, new X))
      .flatMap { x =>
        IndexedStateT(_ => Eval.now(new Y, new Y)).map(x -> _) // Fails to infer the types for IndexedStateT[Eval, X, Y, Y] "missing parameter type"
      }

Usage context

I'm using a specialised type of State monad in application code

type HListState[SA <: HList, A] = IndexedStateT[Eval, SA, A :: SA, A]
  object HListState {
    def apply[SA <: HList, A](fn: SA => A): HListState[SA, A] = IndexedStateT[Eval, SA, A :: SA, A](sa => Eval.now((fn(sa) :: sa, fn(sa))))
  }

// Type inference works here
val res3: IndexedStateT[Eval, HNil, Y :: X :: HNil, Y] =
  HListState[HNil, X](_ => new X).flatMap { x =>
    HListState(_ => new Y)
  }

// Inference not so good :(
val res4: IndexedStateT[Eval, HNil, Y :: X :: HNil, (X, Y)] = 
  HListState[HNil, X](_ => new X).flatMap { x =>
    HListState(_ => new Y).map(x -> _)  // <--- type inference fails here :( "missing parameter type"
  }

Is there a way to get the type inference working in this case?

Pulasthi Bandara
  • 526
  • 4
  • 16

1 Answers1

0

Without map, the compiler can use the expected type of res1 to figure out type parameters of flatMap and so of IndexedStateT. But when you add map, there's no expected type for the IndexedStateT call.

I can't be sure without testing it, but I expect that specifying the parameter type (SA) should be enough, the rest should be inferred without problems:

IndexedStateT { _: X => Eval.now(new Y, new Y) }.map(x -> _)
Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487