typeTagged[U] = { typeTag = U }
type @@[T, U] = T with Tagged[U]
Suppose we want a way to express mass using kilogram,
because kg is the international standard of unit.
Normally we would pass in Double and call it a day,
but we can’t distinguish that from other Double values.
Can we use case class for this?
1
2
3
4
5
6
7
8
9
case class KiloGram(value: Double)
// we have to call x.value every time we need to extract the value out of it.
// Tagged type to the rescue.
sealed trait KiloGram
def KiloGram[A](a: A): A @@ KiloGram = Tag[A, KiloGram](a)
val mass = KiloGram(20.0)
2 * mass // res2: Double = 40.0
A @@ KiloGram is an infix notation of scalaz.@@[A, KiloGram]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
scala> sealed trait JoulePerKiloGram
defined trait JoulePerKiloGram
scala> def JoulePerKiloGram[A](a: A): A @@ JoulePerKiloGram = Tag[A, JoulePerKiloGram](a)
JoulePerKiloGram: [A](a: A)scalaz.@@[A,JoulePerKiloGram]
scala> def energyR(m: Double @@ KiloGram): Double @@ JoulePerKiloGram =
| JoulePerKiloGram(299792458.0 * 299792458.0 * m)
energyR: (m: scalaz.@@[Double,KiloGram])scalaz.@@[Double,JoulePerKiloGram]
scala> energyR(mass)
res4: scalaz.@@[Double,JoulePerKiloGram] = 1.79751035747363533E18
scala> energyR(10.0)
<console>:18: error: type mismatch;
found : Double(10.0)
required: scalaz.@@[Double,KiloGram]
(which expands to) Double with AnyRef{type Tag = KiloGram} energyR(10.0)
trait FunctorLaw {
/** The identity function, lifted, is a no-op. */
defidentity[A](fa: F[A])(implicit FA: Equal[F[A]]): Boolean = FA.equal(map(fa)(x => x), fa)
/**
* A series of maps may be freely rewritten as a single map on a
* composed function.
*/
defassociative[A, B, C](fa: F[A], f1: A => B, f2: B => C)(implicit FC: Equal[F[C]]): Boolean =
FC.equal(map(map(fa)(f1))(f2), map(fa)(f2 compose f1))
}
$ sbt test:console
[info] Starting scala interpreter...
[info]
import scalaz._
import Scalaz._
import scalacheck.ScalazProperties._
import scalacheck.ScalazArbitrary._
import scalacheck.ScalaCheckBinding._
Welcome to Scala version2.10.3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_45).
Type in expressions to have them evaluated.
Type :help for more information.
scala> functor.laws[List].check
这些规则可能会被破坏
Applicative Laws
1
2
3
4
5
6
7
8
9
10
11
12
13
trait ApplicativeLaw extends FunctorLaw {
def identityAp[A](fa: F[A])(implicit FA: Equal[F[A]]): Boolean =
FA.equal(ap(fa)(point((a: A) => a)), fa)defcomposition[A, B, C](fbc: F[B => C], fab: F[A => B], fa: F[A])(implicit FC: Equal[F[C]]) =
FC.equal(ap(ap(fa)(fab))(fbc), ap(fa)(ap(fab)(ap(fbc)(point((bc: B => C) => (ab: A => B) => bc compose ab)))))defhomomorphism[A, B](ab: A => B, a: A)(implicit FB: Equal[F[B]]): Boolean =
FB.equal(ap(point(a))(point(ab)), point(ab(a)))definterchange[A, B](f: F[A => B], a: A)(implicit FB: Equal[F[B]]): Boolean =
FB.equal(ap(point(a))(f), ap(f)(point((f: A => B) => f(a))))
}
if we don’t know if the contents are monoids,
we can’t use mappend between them, so what are we to do? Well,
one thing we can do is to just discard the second
value and keep the first one. For this, the First a type exists.
trait Foldable[F[_]] { self =>
/** Map each element of the structure to a [[scalaz.Monoid]], and combine the results. */
deffoldMap[A,B](fa: F[A])(f: A => B)(implicit F: Monoid[B]): B
/**Right-associative fold of a structure. */
deffoldRight[A, B](fa: F[A], z: => B)(f: (A, => B) => B): B
...
}
/** Wraps a value `self` and provides methods related to `Foldable` */
trait FoldableOps[F[_],A] extends Ops[F[A]] {
implicit defF: Foldable[F]
////
final deffoldMap[B: Monoid](f: A => B = (a: A) => a): B = F.foldMap(self)(f)
final deffoldRight[B](z: => B)(f: (A, => B) => B): B = F.foldRight(self, z)(f)
final deffoldLeft[B](z: B)(f: (B, A) => B): B = F.foldLeft(self, z)(f)
final deffoldRightM[G[_], B](z: => B)(f: (A, => B) => G[B])(implicit M: Monad[G]): G[B] = F.foldRightM(self, z)(f)
final deffoldLeftM[G[_], B](z: B)(f: (B, A) => G[B])(implicit M: Monad[G]): G[B] = F.foldLeftM(self, z)(f)
final deffoldr[B](z: => B)(f: A => (=> B) => B): B = F.foldr(self, z)(f)
final deffoldl[B](z: B)(f: B => A => B): B = F.foldl(self, z)(f)
final deffoldrM[G[_], B](z: => B)(f: A => ( => B) => G[B])(implicit M: Monad[G]): G[B] = F.foldrM(self, z)(f)
final deffoldlM[G[_], B](z: B)(f: B => A => G[B])(implicit M: Monad[G]): G[B] = F.foldlM(self, z)(f)
final deffoldr1(f: (A, => A) => A): Option[A] = F.foldr1(self)(f)
final deffoldl1(f: (A, A) => A): Option[A] = F.foldl1(self)(f)
final defsumr(implicit A: Monoid[A]): A = F.foldRight(self, A.zero)(A.append)
final defsuml(implicit A: Monoid[A]): A = F.foldLeft(self, A.zero)(A.append(_, _))
final deftoList: List[A] = F.toList(self)
final deftoIndexedSeq: IndexedSeq[A] = F.toIndexedSeq(self)
final deftoSet: Set[A] = F.toSet(self)
final deftoStream: Stream[A] = F.toStream(self)
final defall(p: A => Boolean): Boolean = F.all(self)(p)
final def ∀(p: A => Boolean): Boolean = F.all(self)(p)
final defallM[G[_]: Monad](p: A => G[Boolean]): G[Boolean] = F.allM(self)(p)
final defanyM[G[_]: Monad](p: A => G[Boolean]): G[Boolean] = F.anyM(self)(p)
final defany(p: A => Boolean): Boolean = F.any(self)(p)
final def ∃(p: A => Boolean): Boolean = F.any(self)(p)
final defcount: Int = F.count(self)
final defmaximum(implicit A: Order[A]): Option[A] = F.maximum(self)
final defminimum(implicit A: Order[A]): Option[A] = F.minimum(self)
final deflongDigits(implicit d: A <:< Digit): Long = F.longDigits(self)
final defempty: Boolean = F.empty(self)
final defelement(a: A)(implicit A: Equal[A]): Boolean = F.element(self, a)
final defsplitWith(p: A => Boolean): List[List[A]] = F.splitWith(self)(p)
final defselectSplit(p: A => Boolean): List[List[A]] = F.selectSplit(self)(p)
final defcollapse[X[_]](implicit A: ApplicativePlus[X]): X[A] = F.collapse(self)
final defconcatenate(implicit A: Monoid[A]): A = F.fold(self)
final deftraverse_[M[_]:Applicative](f: A => M[Unit]): M[Unit] = F.traverse_(self)(f)
////
}
Monads are a natural extension applicative functors, and they provide
a solution to the following problem: If we have a value with context, m a,
how do we apply it to a function that takes a normal a and returns a value with a contex
case class KnightPos(c: Int, r: Int) {
// 移动一步能到达的位置
def move: List[KnightPos] =
for {
KnightPos(c2, r2) <- List(KnightPos(c + 2, r - 1), KnightPos(c + 2, r + 1),
KnightPos(c - 2, r - 1), KnightPos(c - 2, r + 1),
KnightPos(c + 1, r - 2), KnightPos(c + 1, r + 2),
KnightPos(c - 1, r - 2), KnightPos(c - 1, r + 2)) if (
((1 |-> 8) contains c2) && ((1 |-> 8) contains r2))
} yield KnightPos(c2, r2)
// 移动三步
def in3: List[KnightPos] =
for {
first <- move
second <- first.move
third <- second.move
} yield third // 移动三步是否能到达这个位置
def canReachIn3(end: KnightPos): Boolean = in3containsend
}
Writer
Whereas the Maybe monad is for values with an added context of
failure, and the list monad is for nondeterministic values, Writer
monad is for values that have another value attached that acts as a
sort of log value.
1
2
3
4
5
6
7
8
9
10
11
12
def isBigGang(x: Int): (Boolean, String) =
(x > 9, "Compared gang size to 9.")
implicit class PairOps[A](pair: (A, String)) {
def applyLog[B](f: A => (B, String)): (B, String) = {
val (x, log) = pair val (y, newlog) = f(x) (y, log ++ newlog)
}
}
(3, "Smallish gang.") applyLog isBigGang // (false,Smallish gang.Compared gang size to 9.)
version 2
1
2
3
4
5
6
7
8
9
10
implicit class PairOps[A, B: Monoid](pair: (A, B)) {
def applyLog[C](f: A => (C, B)): (C, B) = {
val (x, log) = pair val (y, newlog) = f(x) (y, log |+| newlog)
}
}
// (false,Smallish gang.Compared gang size to 9.)
(3, "Smallish gang.") applyLog isBigGang
// function as a functor
scala> val f = (_: Int) * 5
f: Int => Int = <function1>
scala> val g = (_: Int) + 3
g: Int => Int = <function1>
scala> (g map f)(8)
res22: Int = 55// function as a applicative
scala> val f = ({(_: Int) * 2} |@| {(_: Int) + 10}) {_ + _}
f: Int => Int = <function1>
scala> f(3)
res35: Int = 19// function as a monad
scala> val addStuff: Int => Int = for {
a <- (_: Int) * 2
b <- (_: Int) + 10
} yield a + b
addStuff: Int => Int = <function1>
scala> addStuff(3)
res39: Int = 19