Как я могу сделать экземпляр Kleisli EitherT в Scala Cats?

Я потратил некоторое время на взлом этого и до сих пор не могу заставить систему типов согласиться со мной, что эта абстракция действительно

ObjectMapper => A => Either[Throwable, B]

Мой текущий тип выглядит

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]

Чтобы проверить создание этого типа, я написал очень простую функцию, которая принимает json String и возвращает Either[Throwable, JsonNode]

val makeJsonNode: JsonParser[String, JsonNode] =
  Kleisli(mapper => EitherT(Reader(json => tryToEither(Try(mapper.readTree(json))))))

Я получаю это сообщение об ошибке:

[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

Я понимаю, что этот тип немного громоздок и, безусловно, может быть улучшен (и, вероятно, излишним), но сейчас я углубляюсь в это, чтобы узнать больше о Cats и системе типов Scala для моего личного роста. Что Scala пытается сказать мне, что это неправильно, и как мне это исправить?

1 ответ

Основная проблема - недостающие типы параметров, попробуйте

Kleisli((mapper: ObjectMapper) => EitherT(Reader((json: String) => tryToEither(Try(mapper.readTree(json))))))

Вы можете использовать лямбду без указания типа параметра только тогда, когда есть ожидаемый тип, дающий эту информацию, и в этом случае makeJsonNode: JsonParser[String, JsonNode] кажется, не достаточно.

Другие вопросы по тегам