为了使任何东西都可以在monad上下文中操作,如果使用Haskell-我只需在任何地方为给定类型添加Monad类的实现即可。因此,我完全不涉及数据类型定义的来源。像(人造的)
data Z a = MyZLeft a | MyZRight a
swap (MyZLeft x) = MyZRight x
swap (MyZRight x) = MyZLeft x
instance Monad Z where
return a = MyZRight a
(>>=) x f = case x of
MyZLeft s -> swap (f s)
MyZRight s -> swap (f s)
所以我没有触及Z的定义,而是将其作为单子
如何在Scala中做到这一点?似乎除了混合一些特征并定义方法map / flatMap / filter / withFilter之外,别无选择。
最佳答案
看一下scalaz
:
// You could use implementation in the end of this answer instead of this import
import scalaz._, Scalaz._
sealed trait Z[T]
case class MyZLeft[T](t: T) extends Z[T]
case class MyZRight[T](t: T) extends Z[T]
def swap[T](z: Z[T]) = z match {
case MyZLeft(t) => MyZRight(t)
case MyZRight(t) => MyZLeft(t)
}
implicit object ZIsMonad extends Monad[Z] {
def point[A](a: => A): Z[A] = MyZRight(a)
def bind[A, B](fa: Z[A])(f: A => Z[B]): Z[B] = fa match {
case MyZLeft(t) => swap(f(t))
case MyZRight(t) => swap(f(t))
}
}
用法:
val z = 1.point[Z]
// Z[Int] = MyZRight(1)
z map { _ + 2 }
// Z[Int] = MyZLeft(3)
z >>= { i => MyZLeft(i + "abc") }
// Z[String] = MyZRight(1abc)
z >>= { i => (i + "abc").point[Z] }
// Z[String] = MyZLeft(1abc)
for-comprehensions
(similar to do-notation):for {
i <- z
j <- (i + 1).point[Z]
k = i + j
} yield i * j * k
// Z[Int] = MyZRight(6)
另请参见Scalaz cheatsheet和Learning scalaz。
scalaz
中没有魔术-您可以在没有scalaz
的情况下实现。相关:Typeclases in Scala & Haskell。
如果不想使用
Monad
,则使用语法最简单地实现scalaz
:import scala.language.higherKinds
trait Monad[M[_]] {
def point[A](a: => A): M[A]
def bind[A, B](fa: M[A])(f: A => M[B]): M[B]
}
implicit class MonadPointer[A](a: A) {
def point[M[_]: Monad] = implicitly[Monad[M]].point(a)
}
implicit class MonadWrapper[M[_]: Monad, A](t: M[A]) {
private def m = implicitly[Monad[M]]
def flatMap[B](f: A => M[B]): M[B] = m.bind(t)(f)
def >>=[B](f: A => M[B]): M[B] = flatMap(f)
def map[B](f: A => B): M[B] = m.bind(t)(a => m.point(f(a)))
def flatten[B](implicit f: A => M[B]) = m.bind(t)(f)
}
关于scala - 在Scala中将任意类作为monad实例,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20673717/