给出定义:
trait Functor[F[_]]:
extension [A](fa: F[A]) def map[B](f: A => B): F[B]
trait Monad[F[_]] extends Functor[F]:
def unit[A](a: => A): F[A]
extension [A](fa: F[A])
def flatMap[B](f: A => F[B]): F[B]
def map[B](f: A => B): F[B] =
flatMap(f.andThen(unit))
object MonadSyntax:
// 'fA' is the thing on which the method >>= is invoked.
extension [F[_], A](fA: F[A])(using mA: Monad[F])
def >>=[B](f: A => F[B]): F[B] = mA.flatMap(fA)(f)
字符串
我想使用ScalaTest和ScalaCheck编写测试来验证三个Monad定律。我不想对每个Monad示例重复测试,我想让测试通用化。我的尝试如下:
trait MonadLaws[F[_]] { this: AnyFunSpec & ScalaCheckPropertyChecks =>
// Monad[F].unit(x).flatMap(f) === f(x)
def leftIdentity[A: Arbitrary, B: Arbitrary](
using arbAToFB: Arbitrary[A => F[B]],
ma: Monad[F]
): Unit =
it("should satisfy the left identity law"):
forAll { (x: A, f: A => F[B]) =>
(ma.unit(x) >>= f) shouldBe f(x)
}
// m.flatMap(Monad[F].unit) === m
def rightIdentity[A: Arbitrary](using eqM: Equality[Monad[F]], ma: Monad[F]): Unit =
it("should satisfy the right identity law"):
val left = for
a: A <- ma
yield summon[Monad[F]].unit(a)
left shouldBe ma
// m.flatMap(f).flatMap(g) === m.flatMap { x => f(x).flatMap(g) }
def associativityLaw[A: Arbitrary, B: Arbitrary, C: Arbitrary](
using arbAToFB: Arbitrary[A => F[B]],
arbBToFB: Arbitrary[B => F[C]],
ma: Monad[F],
eqM: Equality[Monad[F]]
): Unit =
it("should satisfy the associativity law"):
forAll { (f: A => F[B], g: B => F[C]) =>
ma.flatMap(f).flatMap(g) shouldBe m.flatMap(x => f(x).flatMap(g))
}
}
型
然后,一个特定的Monad示例将运行如下测试:
class OptionMonadLawsSpec extends AnyFunSpec with ScalaCheckPropertyChecks with MonadLaws[Option]:
describe("Options form a Monad"):
import MonadInstances.optionMonad
leftIdentity[Int, Int]
型
为简洁起见,省略了导入。
问题是第二个和第三个测试无法编译,都失败了:
Found: A => F[A]
Required: F[A²]
where: A is a type in method rightIdentity
A² is a type variable with constraint
F is a type in trait MonadLaws with bounds <: [_] =>> Any
型
我绞尽脑汁想了一个多小时,还是不能把类型弄对。还有,我如何调用Monad[F].unit
,其中unit
是一个示例方法?
1条答案
按热度按时间ruoxqz4g1#
@LuisMiguelMejíaSuárez在Typelevel Discord频道帮助我编译代码。我还没有彻底测试它,但类型检查出来了,他也很好心地指出了一个基本的误解。
字符串