Как правильно использовать MonadError? - PullRequest
1 голос
/ 18 июня 2020

У меня есть следующий код, который не компилируется:

final class DbSystemEnvironment[F[_] : MonadError[F, Throwable]] private(env: Environment[F])
  extends DbSetting[F] {
  override def read(url: String, user: String, pw: String): F[DbParameter] =
    (for {
      a <- OptionT(env.get(url))
      b <- OptionT(env.get(user))
      c <- OptionT(env.get(pw))
    } yield DbParameter(a, b, c))
      .value
      .flatMap {
        case Some(v) => v.pure[F]
        case None => DbSettingError.raiseError[F, DbParameter]
      }

}

Компилятор жалуется:

[error] db/DbSystemEnvironment.scala:10:38: cats.MonadError[F,Throwable] does not take type parameters
[error] final class DbSystemEnvironment[F[_] : MonadError[F, Throwable]] private(env: Environment[F])
[error]                                      ^
[error] db/DbSystemEnvironment.scala:16:9: Could not find an instance of Functor for F
[error]       c <- OptionT(env.get(pw))
[error]         ^
[error] db/DbSystemEnvironment.scala:20:27: value pure is not a member of Any
[error]         case Some(v) => v.pure[F]
[error]                           ^
[error] db/DbSystemEnvironment.scala:21:37: value raiseError is not a member of object io.databaker.db.DbSettingError
[error]         case None => DbSettingError.raiseError[F, DbParameter]

Кажется, я неправильно использую MonadError.

Остальной код:

final case class DbParameter(url: String, user: String, pw: String)

trait Environment[F[_]] {
  def get(v: String) : F[Option[String]]
}

object Environment {

  def apply[F[_]](implicit ev: Environment[F]): ev.type = ev

  def impl[F[_]: Sync]: Environment[F] = new Environment[F] {
    override def get(v: String): F[Option[String]] =
      Sync[F].delay(sys.env.get(v))
  }
}

Как скомпилировать код?

1 Ответ

2 голосов
/ 18 июня 2020

Проблема здесь в синтаксисе ограничения. Для конструктора типа с одним параметром (например, Monad) вы можете написать class Foo[F[_]: Monad]. Когда вам нужно «частично применить» конструктор типа с несколькими параметрами, например MonadError, ситуация немного иная.

Если вы используете kind-проектор, вы можете написать следующее:

class DbSystemEnvironment[F[_]: MonadError[*[_], Throwable]]

Это нестандартный синтаксис, и в настоящее время он не включен в частичную поддержку совместимости -Ykind-projector Дотти. Я бы порекомендовал просто удалить неявный список параметров:

class DbSystemEnvironment[F[_]](implicit F: MonadError[F, Throwable]])

Это делает именно то, что вы хотите, не требует дополнительного плагина компилятора и гораздо более надежен в будущем.

...