这个例子来源于scala圣经级教程《Functional Programming in Scala》,虽然原书的随书代码可以找到这些类的影子,但却没有关于如何使用这些类的示例代码,本人在阅读此书期间,除了跟着书中的代码敲了一遍之外,还写了一些测试代码进行验证,贴出来作为blog主要是为了方便自己,也为那些同样在阅读此书的人参考。注释不多,本人也不可能写太多,因为这本书不是简单的入门书,而是一本进阶,升华用的内涵书籍,三言两语也解释不清其中的很多细节,如果看不懂,但是又感兴趣的就去看原书吧……
Monad是可以认为是这样一种结构,这种结构能够将一个值放入一个可计算的上下文中(A monad is a structure that puts a value in a computational context)。
package monad
import monad.Monad.{getState, setState}
import parallelism.Par._
import parallelism._
import parsing._
import testing._
import state._
import scala.language.higherKinds
trait Functor[F[_]] {
def map[A,B](fa: F[A])(f: A => B): F[B]
def distribute[A,B](fab: F[(A, B)]): (F[A], F[B]) =
(map(fab)(_._1), map(fab)(_._2))
def codistribute[A,B](e: Either[F[A], F[B]]): F[Either[A, B]] = e match {
case Left(fa) => map(fa)(Left(_))
case Right(fb) => map(fb)(Right(_))
}
}
object Functor {
val listFunctor = new Functor[List] {
def map[A,B](as: List[A])(f: A => B): List[B] = as map f
}
}
trait Monad[F[_]] extends Functor[F] {
def unit[A](a: => A): F[A]
def flatMap[A,B](ma: F[A])(f: A => F[B]): F[B] =
join(map(ma)(f))
def map[A,B](ma: F[A])(f: A => B): F[B] =
flatMap(ma)(a => unit(f(a)))
def map2[A,B,C](ma: F[A], mb: F[B])(f: (A, B) => C): F[C] =
flatMap(ma)(a => map(mb)(b => f(a, b)))
def sequence[A](lma: List[F[A]]): F[List[A]] =
lma.foldRight(unit(List[A]()))((ma, mla) => map2(ma, mla)(_ :: _))
def traverse[A,B](la: List[A])(f: A => F[B]): F[List[B]] =
la.foldRight(unit(List[B]()))((a, mlb) => map2(f(a), mlb)(_ :: _))
// For `List`, the `replicateM` function will generate a list of lists.// It will contain all the lists of length `n` with elements selected from the// input list.// For `Option`, it will generate either `Some` or `None` based on whether the// input is `Some` or `None`. The `Some` case will contain a list of length `n`// that repeats the element in the input `Option`.// The general meaning of `replicateM` is described very well by the// implementation `sequence(List.fill(n)(ma))`. It repeats the `ma` monadic value// `n` times and gathers the results in a single value, where the monad `M`// determines how values are actually combined.// Recursive version:
def _replicateM[A](n: Int, ma: F[A]): F[List[A]] =
if (n <= 0) unit(List[A]()) else map2(ma, _replicateM(n - 1, ma))(_ :: _)
// Using `sequence` and the `List.fill` function of the standard library:
def replicateM[A](n: Int, ma: F[A]): F[List[A]] =
sequence(List.fill(n)(ma))
def compose[A,B,C](f: A => F[B], g: B => F[C]): A => F[C] =
a => flatMap(f(a))(g)
def _flatMap[A,B](ma: F[A])(f: A => F[B]): F[B] =
compose((_:Unit) => ma, f)(())
def join[A](mma: F[F[A]]): F[A] = flatMap(mma)(ma => ma)
def filterM[A](ms: List[A])(f: A => F[Boolean]): F[List[A]] =
ms.foldRight(unit(List[A]()))((x,y) =>
compose(f, (b: Boolean) => if (b) map2(unit(x),y)(_ :: _) else y)(x))
}
case class Reader[R, A](run: R => A)
object Monad {
val genMonad = new Monad[Gen] {
def unit[A](a: => A): Gen[A] = Gen.unit(a)
override def flatMap[A,B](ma: Gen[A])(f: A => Gen[B]): Gen[B] =
ma flatMap f
}
val parMonad = new Monad[Par] {
def unit[A](a: => A) = Par.unit(a)
override def flatMap[A,B](ma: Par[A])(f: A => Par[B]) = Par.flatMap(ma)(f)
}
def parserMonad[P[+_]](p: Parsers[P]) = new Monad[P] {
def unit[A](a: => A) = p.succeed(a)
override def flatMap[A,B](ma: P[A])(f: A => P[B]) = p.flatMap(ma)(f)
}
val optionMonad = new Monad[Option] {
def unit[A](a: => A) = Some(a)
override def flatMap[A,B](ma: Option[A])(f: A => Option[B]) = ma flatMap f
}
val streamMonad = new Monad[Stream] {
def unit[A](a: => A) = Stream(a)
override def flatMap[A,B](ma: Stream[A])(f: A => Stream[B]) = ma flatMap f
}
val listMonad = new Monad[List] {
def unit[A](a: => A) = List(a)
override def flatMap[A,B](ma: List[A])(f: A => List[B]) = ma flatMap f
}
// Since `State` is a binary type constructor, we need to partially apply it// with the `S` type argument. Thus, it is not just one monad, but an entire// family of monads, one for each type `S`. One solution is to create a class// `StateMonads` that accepts the `S` type argument and then has a _type member_// for the fully applied `State[S, A]` type inside:
class StateMonads[S] {
type StateS[A] = State[S, A]
// We can then declare the monad for the `StateS` type constructor:
val monad = new Monad[StateS] {
def unit[A](a: => A): State[S, A] = State(s => (a, s))
override def flatMap[A,B](st: State[S, A])(f: A => State[S, B]): State[S, B] =
st flatMap f
}
}
// But we don't have to create a full class like `StateMonads`. We can create// an anonymous class inline, inside parentheses, and project out its type member,// `lambda`:
def stateMonad[S] = new Monad[({type lambda[x] = State[S, x]})#lambda] {
def unit[A](a: => A): State[S, A] = State(s => (a, s))
override def flatMap[A,B](st: State[S, A])(f: A => State[S, B]): State[S, B] =
st flatMap f
}
val idMonad = new Monad[Id] {
def unit[A](a: => A) = Id(a)
override def flatMap[A,B](ida: Id[A])(f: A => Id[B]): Id[B] = ida flatMap f
}
def getState[S]: State[S,S] = State(s => (s,s))
def setState[S](s: S): State[S,Unit] = State(_ => ((),s))
val F = stateMonad[Int]
def _zipWithIndex[A](as: List[A]): List[(Int,A)] =
as.foldLeft(F.unit(List[(Int, A)]()))((acc,a) => for {
xs <- acc
n <- getState
_ <- setState(n + 1)
} yield (n, a) :: xs).run(0)._1.reverse
def zipWithIndex[A](as: List[A]): List[(A, Int)] =
as.foldLeft(F.unit(List[(A, Int)]()))((acc,a) => for {
xs <- acc
n <- getState
_ <- setState(n + 1)
} yield (a, n) :: xs).run(0)._1.reverse
// The action of Reader's `flatMap` is to pass the `r` argument along to both the// outer Reader and also to the result of `f`, the inner Reader. Similar to how// `State` passes along a state, except that in `Reader` the "state" is read-only.// The meaning of `sequence` here is that if you have a list of functions, you can// turn it into a function that takes one argument and passes it to all the functions// in the list, returning a list of the results.// The meaning of `join` is simply to pass the same value as both arguments to a// binary function.// The meaning of `replicateM` is to apply the same function a number of times to// the same argument, returning a list of the results. Note that if this function// is _pure_, (which it should be), this can be exploited by only applying the// function once and replicating the result instead of calling the function many times.// This means the Reader monad can override replicateM to provide a very efficient// implementation.
def readerMonad[R] = new Monad[({type f[x] = Reader[R,x]})#f] {
def unit[A](a: => A): Reader[R, A] = Reader(_ => a)
override def flatMap[A,B](st: Reader[R, A])(f: A => Reader[R, B]): Reader[R, B] =
Reader(r => f(st.run(r)).run(r))
}
}
case class Id[A](value: A) {
def map[B](f: A => B): Id[B] = Id(f(value))
def flatMap[B](f: A => Id[B]): Id[B] = f(value)
}
object Reader {
def ask[R]: Reader[R, R] = Reader(r => r)
}
object MonadTest {
def main(args: Array[String]): Unit = {
val li = List("one", "two", "three", "four", "five", "six")
val monadZipRes = Monad.zipWithIndex(li)
val zipRes = li.zipWithIndex
println(monadZipRes)
println(zipRes)
//验证自实现的zipWithIndex与scala库自带的zipWithIndex是不是给出一致的结果
val prop = Prop.forAll(Gen.choose(200, 301).listOf(10)) { intList =>
//左边是scala的List数据结构自带的函数(zipWithIndex)
intList.zipWithIndex == Monad.zipWithIndex(intList)
}
Prop.run(prop)
val idMonad: Monad[Id] = Monad.idMonad
val id4 = Id(4)
val anotherId4 = idMonad.unit(4)
println(id4)
println(anotherId4)
val replicaM = Monad.idMonad.replicateM(5, id4)
println(replicaM)
val id4Tuple = Monad.idMonad.flatMap(id4)((a: Int) => Monad.idMonad.map(id4)(b => (a, b)))
println(id4Tuple)
val anotherId4Tuple = for {
l <- id4
r <- id4.map(x => x)
} yield (l, r)
println(anotherId4Tuple)
val idHelloMonad = for {
a <- Id("hello ")
b <- Id("monad")
} yield a + b
println(idHelloMonad.value == "hello " + "monad")
val s0 = Monad.F.unit(0)
val valueAndState = for{
a <- s0 //a 是老的状态对应的函数值
s <- getState //s 代表那个老的状态本身
_ <- setState(s + 1) // 老的状态加1, 然后作为最新的状态
} yield (a, s) // 将元组(a,s)设置为新的状态产出的函数值
println(valueAndState.run(0))
// 上述语句采用for推导得到一个新的状态:valueAndState,// 这里采用flatMap和map调用得到一个类似功能的状态: anotherValueAndState//valueAndState 和 anotherValueAndState 是等价的
val anotherValueAndState = s0.flatMap(a => //a 是老的状态对应的函数值
getState.flatMap(s => //s 代表那个老的状态本身
setState(s + 1).map( // 老的状态加1, 然后作为最新的状态
_ => (a, s) // 将元组(a,s)设置为新的状态产出的函数值
)
)
)
//将打印出: ((0,0),1),// 其中元组 (0,0)的第一个元素0是输入老的状态值0得到的函数值, 右边的0代表那个老的状态值。 剩下的1表示新的状态值//老的状态对应的函数值和老的状态本身构成的元组(也即(0, 0)将被当作新的状态的函数值
println(anotherValueAndState.run(0))
}
}