Reputation: 1414
I've spent a while hacking on this and still can't quite get the type system to agree with me that this abstraction is really a
ObjectMapper => A => Either[Throwable, B]
My current type looks like
import cats._
import cats.data.{Reader, Kleisli, EitherT}
import cats.implicits._
import com.fasterxml.jackson.databind.{ObjectMapper, JsonNode}
type JsonParser[A, B] = Kleisli[EitherT[Reader[A, ?], Throwable, ?], ObjectMapper, B]
To test instantiating this type, I've written a very simple function that takes a json String
and returns an Either[Throwable, JsonNode]
val makeJsonNode: JsonParser[String, JsonNode] =
Kleisli(mapper => EitherT(Reader(json => tryToEither(Try(mapper.readTree(json))))))
I'm getting this error message:
[info] Compiling 6 Scala sources to .../scala-2.11/classes...
[error] Test.scala:140: missing parameter type
[error] Kleisli(mapper => EitherT(Reader(json => tryToEither(Try(mapper.readTree(json))))))
[error] ^
[error] Test.scala:140: missing parameter type
[error] Kleisli(mapper => EitherT(Reader(json => tryToEither(Try(mapper.readTree(json))))))
[error] ^
[error] Test.scala:140: no type parameters for method apply: (value: F[Either[A,B]])cats.data.EitherT[F,A,B] in object EitherT exist so that it can be applied to arguments (cats.data.Reader[Any,Nothing])
[error] --- because ---
[error] argument expression's type is not compatible with formal parameter type;
[error] found : cats.data.Reader[Any,Nothing]
[error] (which expands to) cats.data.Kleisli[cats.Id,Any,Nothing]
[error] required: ?F[Either[?A,?B]]
[error] Kleisli(mapper => EitherT(Reader(json => tryToEither(Try(mapper.readTree(json))))))
[error] ^
[error] Test.scala:140: type mismatch;
[error] found : cats.data.Reader[Any,Nothing]
[error] (which expands to) cats.data.Kleisli[cats.Id,Any,Nothing]
[error] required: F[Either[A,B]]
[error] Kleisli(mapper => EitherT(Reader(json => tryToEither(Try(mapper.readTree(json))))))
[error] ^
[error] Test.scala:140: no type parameters for method apply: (run: A => F[B])cats.data.Kleisli[F,A,B] in object Kleisli exist so that it can be applied to arguments (<error> => cats.data.EitherT[F,A,B])
[error] --- because ---
[error] argument expression's type is not compatible with formal parameter type;
[error] found : <error> => cats.data.EitherT[F,A,B]
[error] required: ?A => ?F[?B]
[error] Kleisli(mapper => EitherT(Reader(json => tryToEither(Try(mapper.readTree(json))))))
[error] ^
[error] Test.scala:140: type mismatch;
[error] found : cats.data.Kleisli[F,A,B]
[error] required: Test.this.Parser[String,com.fasterxml.jackson.databind.JsonNode]
[error] (which expands to) cats.data.Kleisli[[γ$1$]cats.data.EitherT[[β$0$]cats.data.Kleisli[[A]A,String,β$0$],Throwable,γ$1$],com.fasterxml.jackson.databind.ObjectMapper,com.fasterxml.jackson.databind.JsonNode]
[error] Kleisli(mapper => EitherT(Reader(json => tryToEither(Try(mapper.readTree(json))))))
[error] ^
[error] 6 errors found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 2 s, completed Jun 16, 2017 1:28:17 PM
I realize this type is a bit cumbersome and can definitely be improved (and is probably overkill), but I'm digging into this now in the interest of learning more about Cats and the Scala type system for my own personal growth. What is Scala trying to tell me is wrong, here, and how should I fix this?
Upvotes: 1
Views: 427
Reputation: 170839
The base problem is the missing parameter types, try
Kleisli((mapper: ObjectMapper) => EitherT(Reader((json: String) => tryToEither(Try(mapper.readTree(json))))))
You can only use a lambda without specifying parameter type when there is an expected type giving this information, and in this case makeJsonNode: JsonParser[String, JsonNode]
doesn't seem to be enough.
Upvotes: 1