0

我已经写了两个无标签代数,我想为其中一个写定律。

代数如下:

@newtype case class Variable(v: String)

@newtype case class Value(v: String)

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


@newtype case class DbUrl(v: String)

@newtype case class DbUser(v: String)

@newtype case class DbPw(v: String)

final case class DbParams(url: DbUrl, user: DbUser, pw: DbPw)

trait DbConnector[F[_]] {
  def read(url: DbUrl, user: DbUser, pw: DbPw): F[DbParams]
}

口译员如下:

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: Variable): F[Option[Value]] =
      Sync[F].delay(sys.env.get(v.v).map(a => Value(a)))
  }
}



final case class LiveDbConnector[F[_] : MonadError[*[_], Throwable]](env: Environment[F]) extends DbConnector[F] {
  override def read(url: DbUrl, user: DbUser, pw: DbPw): F[DbParams] =
    (for {
      a <- OptionT(env.get(Variable(url.v)))
      b <- OptionT(env.get(Variable(user.v)))
      c <- OptionT(env.get(Variable(pw.v)))
    } yield DbParams(DbUrl(a.v), DbUser(b.v), DbPw(c.v)))
      .value
      .flatMap {
        case Some(v) => v.pure[F]
        case None => DbSettingError.raiseError[F, DbParams]
      }
}

object DbConnector {

  def impl[F[_] : MonadError[*[_], Throwable]](env: Environment[F])
  : DbConnector[F] =
    new LiveDbConnector[F](env)


在函数式编程中,有 Monoid、Monads 等规律。

我的问题是:

  1. 我的代数是否需要法律或编写单元测试就足够了?
  2. 法律和单元测试有什么区别?
  3. 我应该如何写DbConnector代数定律
4

1 回答 1

1

您将数学定律和合理性与程序的正确性混淆了。

首先,Monad、Monoid、Fold 等不是定律。它们是来自范畴论的数学“结构” 。这些“结构”具有它们需要遵守、健全和正确的某些特性。例如,其中一组属性被称为一元定律

数学中的任何一元结构都需要遵守以下 3 条规则:

  1. 左身份
  2. 正确的身份
  3. 关联性

Monad、flatMap 和 pure(或数学中的 join 和 return)的操作必须根据这些定律正确才能正常运行。即pure(a).flatMap(f) == f(a)M.flatMap(pure) == M

在函数式编程中,Monads 是一种从这些数学结构和规律中衍生出来的设计模式。他们描述了一些“可组合的计算”。在猫中 Monad 被定义为typeclass。这种结构符合上述规则。

我应该如何为 DbConnector 代数编写定律

如果你想证明定律,你可能需要使用定理证明器,实际上没有办法在 Scala 中明确地编写或测试定律,但你总是可以编写单元测试来确保你的 Monad 遵守这些定律,testFlatMapLeftIdentity(...)例如等等。

我的代数是否需要法律或编写单元测试就足够了?

简而言之,我想不出代数有明确的规律的情况,除非你的代数描述了一些数学运算集。例如,在您的代码中,上下文绑定MonadError[*[_], Throwable]]需要Monad[F]在范围内,它需要遵守这些法律,假设您使用的是 commonIO, Task, Future等,猫已经做到了,所以您不必担心这些法律。如果您决定实现自己的效果类型或编写新的 Monad 实现,您将需要确保遵守这些规则,但您的代码中没有什么需要您担心它们。为这个代数编写好的单元测试就足够了。

于 2020-06-20T16:27:07.500 回答