【问题标题】:Replace scalaz ListT with semantically equivalent cats functionality用语义等效的猫功能替换 scalaz ListT
【发布时间】:2020-05-31 08:00:16
【问题描述】:

cats 确实 not 提供了 ListT monad 转换器,那么我们如何重写以下 snippet ,它使用 scalaz ListT 来理解到语义上等效的猫中的 sn-p

import scalaz._
import ListT._
import scalaz.std.option._

val seeds: Option[List[String]] = Some(List("apple", "orange", "tomato"))
def grow(seed: String): Option[List[String]] = Some(List(seed.toUpperCase))
def family(seed: String, plant: String): Option[List[(String, String)]] = Some(List(seed -> plant))

(for {
  seed    <- listT(seeds)
  plant   <- listT(grow(seed))
  result  <- listT(family(seed, plant))
} yield result).run

这是我尝试使用flatMapflatTraverse

import cats.implicits._

seeds
  .flatMap {
    _.flatTraverse { seed =>
      grow(seed)
        .flatMap {
          _.flatTraverse { plant =>
            family(seed, plant)
          }
        }
    }
  }

这种重构似乎满足了类型检查器,但是我不确定快乐的编译器是否能确保 100% 语义等价。

【问题讨论】:

    标签: list scala scalaz monad-transformers scala-cats


    【解决方案1】:

    Cats 不提供 ListT,因为它违反了关联性 Monad 定律。请参阅Cats FAQassociated proof using scalaz ListT

    您建议的基于.flatTraverse 的以下ListT 实现仍然通过了所有猫核心法律测试(错误?)。

    我没有软件证明方面的经验,但您可能会发现成功的测试足以将这两种实现视为等效。

    ListT 实现

    case class ListT[M[_], A](value: M[List[A]])
    implicit def listTMonad[M[_]: Monad] = new Monad[ListT[M, *]] {
      override def flatMap[A, B](fa: ListT[M, A])(f: A => ListT[M, B]): ListT[M, B] =
        ListT(
          Monad[M].flatMap[List[A], List[B]](fa.value)(
            list => Traverse[List].flatTraverse[M, A, B](list)(a => f(a).value)
          )
        )
      override def pure[A](a: A): ListT[M, A] = ListT(Monad[M].pure(List(a)))
      // unsafe impl, can be ignored for this question
      override def tailRecM[A, B](a: A)(f: A => ListT[M, Either[A, B]]): ListT[M, B] =
        flatMap(f(a)) {
          case Right(b) => pure(b)
          case Left(nextA) => tailRecM(nextA)(f)
        }
    }
    

    sbt

    name := "listT_tests"
    version := "0.1"
    scalaVersion := "2.11.12"
    
    scalacOptions += "-Ypartial-unification"
    
    libraryDependencies ++= Seq(
      "org.typelevel" %% "cats-core" % "2.0.0",
      "org.scalaz" %% "scalaz-core" % "7.2.30",
      "org.scalacheck" %% "scalacheck" % "1.14.1" % "test",
      "org.scalatest" %% "scalatest" % "2.2.6" % "test",
      "org.typelevel" %% "discipline-scalatest" % "1.0.1",
      "org.typelevel" %% "discipline-core" % "1.0.2",
      "org.typelevel" %% "cats-laws" % "2.0.0" % Test,
      "com.github.alexarchambault" %% "scalacheck-shapeless_1.14" % "1.2.3" % Test
    )
    
    addCompilerPlugin("org.typelevel" %% "kind-projector" % "0.11.0" cross CrossVersion.full)
    

    法律测试

    class TreeLawTests extends AnyFunSpec with Checkers with FunSpecDiscipline {
    
      implicit def listTEq[M[_], A] = Eq.fromUniversalEquals[ListT[M, A]]
      checkAll("ListT Monad Laws", MonadTests[ListT[Option, *]].stackUnsafeMonad[Int, Int, String])
    }
    

    法律测试结果

    - monad (stack-unsafe).ap consistent with product + map
    - monad (stack-unsafe).applicative homomorphism
    - monad (stack-unsafe).applicative identity
    - monad (stack-unsafe).applicative interchange
    - monad (stack-unsafe).applicative map
    - monad (stack-unsafe).applicative unit
    - monad (stack-unsafe).apply composition
    - monad (stack-unsafe).covariant composition
    - monad (stack-unsafe).covariant identity
    - monad (stack-unsafe).flatMap associativity
    - monad (stack-unsafe).flatMap consistent apply
    - monad (stack-unsafe).flatMap from tailRecM consistency
    - monad (stack-unsafe).invariant composition
    - monad (stack-unsafe).invariant identity
    - monad (stack-unsafe).map flatMap coherence
    - monad (stack-unsafe).map2/map2Eval consistency
    - monad (stack-unsafe).map2/product-map consistency
    - monad (stack-unsafe).monad left identity
    - monad (stack-unsafe).monad right identity
    - monad (stack-unsafe).monoidal left identity
    - monad (stack-unsafe).monoidal right identity
    - monad (stack-unsafe).mproduct consistent flatMap
    - monad (stack-unsafe).productL consistent map2
    - monad (stack-unsafe).productR consistent map2
    - monad (stack-unsafe).semigroupal associativity
    - monad (stack-unsafe).tailRecM consistent flatMap
    

    【讨论】:

    猜你喜欢
    • 2020-07-21
    • 2012-07-06
    • 1970-01-01
    • 2013-08-09
    • 2021-10-31
    • 2023-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多