Commit 0f38e1e7 by Haochen Xie

update ch10/Monoids.scala

parent 43988716
......@@ -4,10 +4,10 @@ version := "1.0"
scalaVersion := "2.12.1"
libraryDependencies += "org.scalacheck" %% "scalacheck" % "1.13.4" % "test"
libraryDependencies += "org.scalacheck" %% "scalacheck" % "1.13.4"
libraryDependencies += "org.scalactic" %% "scalactic" % "3.0.1"
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.1" % "test"
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.1"
libraryDependencies += "junit" % "junit" % "4.12" % "test"
libraryDependencies += "commons-codec" % "commons-codec" % "1.10"
......
package name.haochenxie.fpscala.ch10
import scala.collection.mutable.ArrayBuffer
import org.scalacheck.Prop.forAll
import org.scalacheck._
trait Monoid[A] {
def op(a1: A, a2: A): A
......@@ -9,16 +10,29 @@ trait Monoid[A] {
object Monoids {
def monoidSpec[A](propName: String, m: Monoid[A])(implicit arb: Arbitrary[A]): Properties = new Properties(propName) {
property("assoc") = forAll {
(a: A, b: A, c: A) => m.op(m.op(a, b), c) == m.op(a, m.op(b, c))
}
property("unit") = forAll {
(a: A) => m.op(m.zero, a) == a && a == m.op(a, m.zero)
}
}
val stringMonoid = new Monoid[String] {
override def op(a1: String, a2: String): String = a1 + a2
override val zero: String = ""
}
val stringMonoidSpec = monoidSpec("StringMonoidSpec", stringMonoid)
def listMonoid[A] = new Monoid[List[A]] {
override def op(a1: List[A], a2: List[A]): List[A] = a1 ++ a2
override val zero: List[A] = Nil
}
val listMonoidSpec = monoidSpec("ListMonoidSpec", listMonoid[Int])
// Exercise 10.1
val intAddition = new Monoid[Int] {
override def op(a1: Int, a2: Int): Int = a1 + a2
......@@ -41,12 +55,13 @@ object Monoids {
}
// Exercise 10.2
// I'm not sure about the expected semantics..
def optionMonoid[A] = new Monoid[Option[A]] {
override def op(a1: Option[A], a2: Option[A]): Option[A] = a1.flatMap(_ => a2)
override def op(a1: Option[A], a2: Option[A]): Option[A] = a1.orElse(a2)
override val zero: Option[A] = Option.empty
}
val optionMonoidSpec = monoidSpec("optionMonoidSpec", optionMonoid[Int])
// Exercise 10.3
def coendoMonoid[A] = new Monoid[A => A] {
// hmm, no idea which one should be called first..
......@@ -75,10 +90,22 @@ object Monoids {
foldMap(as, coendoMonoid[B])(a => z => f(z, a))(z)
}
val foldLeftCorrectness = new Properties("foldLeftCorrectness") {
property("againstListImplementation") = forAll {
(as: List[Double]) => as.foldLeft(132.0)(_/_) == foldLeft(as)(132.0)(_/_)
}
}
def foldRight[A,B](as: List[A])(z: B)(f: (A, B) => B): B = {
foldMap(as, contraendoMonoid[B])(a => z => f(a, z))(z)
}
val foldRightCorrectness = new Properties("foldRightCorrectness") {
property("againstListImplementation") = forAll {
(as: List[Double]) => as.foldRight(132.0)(_/_) == foldRight(as)(132.0)(_/_)
}
}
// Exercise 10.7
def foldMapV[A,B](v: IndexedSeq[A], m: Monoid[B])(f: A => B): B =
if (v.isEmpty) m.zero
......@@ -251,8 +278,19 @@ object MonoidsPlayground {
// println(ordered(Vector(10, 20, 30, 30, 40)))
// println(ordered(Vector(10, 20, 31, 30, 40)))
optionMonoidSpec.check()
foldLeftCorrectness.check()
foldRightCorrectness.check()
println(countWords("the quick brown fox", 6))
println(countWords("the quick brown fox", 2))
println(countWords("the quick brown fox", 100))
println(foldLeft(List[Double](10, 20, 3))(1.0)(_/_))
println(List[Double](10, 20, 3).foldLeft(1.0)(_/_))
println(foldRight(List[Double](10, 20, 3))(1.0)(_/_))
println(List[Double](10, 20, 3).foldRight(1.0)(_/_))
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment