我正在編寫一個庫來通過API訪問Web服務。我定義簡單的類來表示API行動測試副作用monad的法律
case class ApiAction[A](run: Credentials => Either[Error, A])
和執行Web服務的一些功能調用
// Retrieve foo by id
def get(id: Long): ApiAction[Foo] = ???
// List all foo's
def list: ApiAction[Seq[Foo]] = ???
// Create a new foo
def create(name: String): ApiAction[Foo] = ???
// Update foo
def update(updated: Foo): ApiAction[Foo] = ???
// Delete foo
def delete(id: Long): ApiAction[Unit] = ???
,我也做了ApiAction
單子所以
implicit val monad = new Monad[ApiAction] { ... }
我可以做類似
create("My foo").run(c)
get(42).map(changeFooSomehow).flatMap(update).run(c)
get(42).map(_.id).flatMap(delete).run(c)
現在我有麻煩測試它的單子法律
val x = 42
val unitX: ApiAction[Int] = Monad[ApiAction].point(x)
"ApiAction" should "satisfy identity law" in {
Monad[ApiAction].monadLaw.rightIdentity(unitX) should be (true)
}
因爲monadLaw.rightIdentity
使用equal
def rightIdentity[A](a: F[A])(implicit FA: Equal[F[A]]): Boolean =
FA.equal(bind(a)(point(_: A)), a)
並沒有Equal[ApiAction]
。
[error] could not find implicit value for parameter FA: scalaz.Equal[ApiAction[Int]]
[error] Monad[ApiAction].monadLaw.rightIdentity(unitX) should be (true)
[error] ^
問題是,我甚至無法想象它怎麼可能定義Equal[ApiAction]
。 ApiAction
是本質上的一個函數,我不知道任何功能上的平等關係。當然,可以比較運行ApiAction
的結果,但它是不一樣的。
我覺得我在做一些非常錯誤的事情,或者不明白某些重要的東西。所以我的問題是:
- 是否有意義的
ApiAction
是一個monad? - 我設計了
ApiAction
對不對? - 我應該如何測試它的monad法則?
對無限域函數沒有可計算的等式關係。你可以運行一個密封特徵的抽象方法,然後將你的ApiAction作爲派生的case類和case對象來實現。 – 2014-09-01 19:35:55