Skip to content

Instantly share code, notes, and snippets.

@v6ak
Created October 17, 2013 11:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save v6ak/7023402 to your computer and use it in GitHub Desktop.
Save v6ak/7023402 to your computer and use it in GitHub Desktop.
Scala coding Dojo
Úkoly z Functional programming in Scala - různé monoidy.
(Co je to monoid: https://cs.wikipedia.org/wiki/Monoid )
U některých monoidů bylo zadání trošku otevřenější, člověk si musel vymyslet vlastní monoid, který splňuje nějaké podmínky.
Zajímavé je ale spíše to testování.
package com.czechscala.blank
trait Monoid[A]{
def op(a1: A, a2: A): A
def zero: A
}
object IntAddition extends Monoid[Int]{
def op(a1: Int, a2: Int):Int = a1+a2
def zero: Int = 0
}
object IntMultiplication extends Monoid[Int]{
def op(a1: Int, a2: Int): Int = a1*a2
def zero: Int = 1
}
object BooleanOr extends Monoid[Boolean]{
def op(a1: Boolean, a2: Boolean): Boolean = a1 || a2
def zero = false
}
object TrimMonoid extends Monoid[String]{
def op(a1: String, a2: String): String = a1.trim+" "+a2.trim
def zero: String = ""
}
object Hello {
def optionMonoid[T]: Monoid[Option[T]] = new Monoid[Option[T]] {
//def op(a1: Option[T], a2: Option[T]) = a1 orElse a2
def op(a1: Option[T], a2: Option[T]) = a2 orElse a1
def zero = None
}
def endoMonoid[T]: Monoid[T => T] = new Monoid[(T) => T] {
def op(a1: (T) => T, a2: (T) => T) = a1 andThen a2
def zero = identity
}
}
package com.czechscala.blank
import org.scalatest.FunSuite
import Hello._
import org.scalatest.matchers.ShouldMatchers
class HelloTest extends FunSuite with ShouldMatchers {
type AssertEquals[T] = (T, T) => Unit
def defaultAssert[T]: AssertEquals[T] = (left: T, right: T) => assert(left === right)
def testNeutrality[T](monoid: Monoid[T])(value: T)(implicit eq: AssertEquals[T] = defaultAssert[T]){
eq(monoid.op(monoid.zero, value), value)
eq(monoid.op(value, monoid.zero), value)
}
def testAssociativity[T](monoid: Monoid[T])(values: T*)(implicit eq: AssertEquals[T] = defaultAssert[T]){
require(values.size > 2)
eq(values.foldLeft(monoid.zero)(monoid.op), values.foldRight(monoid.zero)(monoid.op))
}
// Int addition
test("int addition") {
IntAddition.op(1, 3) should be (4)
}
test("int addition neutrality"){
-10 to 10 foreach testNeutrality(IntAddition)
}
test("int add assoc"){
testAssociativity(IntAddition)(2, 3, 4)
testAssociativity(IntAddition)(3, 4, 5)
}
// int multiplication
test("test IntMultiplication"){
assert(IntMultiplication.op(5, 6) === 30)
}
test("test multiplication neutrality"){
-10 to 10 foreach testNeutrality(IntMultiplication)
}
test("int mul assoc"){
testAssociativity(IntMultiplication)(2, 3, 4)
testAssociativity(IntMultiplication)(3, 4, 5)
}
// boolean or
test("Boolean or"){
assert(BooleanOr.op(false, false) === false)
assert(BooleanOr.op(false, true) === true)
assert(BooleanOr.op(true, false) === true)
assert(BooleanOr.op(true, false) === true)
}
test("Boolean or neutrality"){
Seq(true, false) foreach testNeutrality(BooleanOr)
}
// Option monoid
test("OptionMonoid"){
/*
assert(optionMonoid[Int].op(Some(2), Some(3)) === Some(2))
assert(optionMonoid[Int].op(Some(2), None) === Some(2))
assert(optionMonoid[Int].op(None, Some(3)) === Some(3))
*/
assert(optionMonoid[Int].op(Some(2), Some(3)) === Some(3))
assert(optionMonoid[Int].op(Some(2), None) === Some(2))
assert(optionMonoid[Int].op(None, Some(3)) === Some(3))
}
test("OptionMonoid neutrality"){
-10 to 10 map {Some(_)} foreach testNeutrality(optionMonoid[Int])
Seq("a", "b", "xxx") map {Some(_)} foreach testNeutrality(optionMonoid[String])
}
test("OptionMonoid associativity"){
testAssociativity(optionMonoid[Int])(Some(1), Some(2), Some(3))
testAssociativity(optionMonoid[Int])(None, Some(2), Some(3))
testAssociativity(optionMonoid[Int])(Some(1), None, Some(3))
testAssociativity(optionMonoid[Int])(Some(1), Some(2), None)
testAssociativity(optionMonoid[Int])(Some(1), None, None)
testAssociativity(optionMonoid[Int])(None, Some(2), None)
testAssociativity(optionMonoid[Int])(None, None, Some(3))
testAssociativity(optionMonoid[Int])(None, None, None)
}
//def m(q: Int): Int => Int = q * _
//def a(q: Int): Int => Int = q + _
def compareFunctions[T](values: T*)(a: T=>T, b: T=>T){
for(value <- values){
assert(a(value) === b(value))
}
}
val compareIntFunctions: AssertEquals[Int => Int] = compareFunctions(-10 to 10 :_*)(_, _)
val compareStringFunctions: AssertEquals[String => String] = compareFunctions(
"""
|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
|
""".stripMargin.split('\n') :_*)(_, _)
test("EndoMonoid"){
compareIntFunctions(endoMonoid[Int].op(2*, 3*), 6*)
compareIntFunctions(endoMonoid[Int].op(2+, 3+), 5+)
}
test("EndoMonoid neutrality"){
testNeutrality(endoMonoid[Int])(2*)(compareIntFunctions)
testNeutrality(endoMonoid[Int])(2+)(compareIntFunctions)
}
test("Endomonoid associativity"){
testAssociativity(endoMonoid[Int])(2*, 3+, 4*)(compareIntFunctions)
testAssociativity(endoMonoid[String])(_.map(_+1 toChar), _.toLowerCase, _.replaceAll("a", "b"))(compareStringFunctions)
}
val compareStringsLoosely: AssertEquals[String] = (left, right) => assert(left.trim === right.trim)
test("TrimMonoid"){
assert(TrimMonoid.op("a", "b") === "a b")
assert(TrimMonoid.op(" a ", " b ") === "a b")
assert(TrimMonoid.op("a ", "b ") === "a b")
assert(TrimMonoid.op(" a x ", "b ") === "a x b")
}
test("Trim neutrality"){
testNeutrality(TrimMonoid)("a")(compareStringsLoosely)
testNeutrality(TrimMonoid)(" a")(compareStringsLoosely)
testNeutrality(TrimMonoid)(" a ")(compareStringsLoosely)
}
test("Trim associativity"){
testAssociativity(TrimMonoid)("dfsd", " dfsdf fgdfgd ", " gfdfg gfd gdf g df g", "gdfg fd gfd g fdftreterg")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment