public
Created

Scala coding Dojo

  • Download Gist
Hello.scala
Scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
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
}
 
}
HelloTest.scala
Scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
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")
}
 
}
README
1 2 3 4 5 6 7
Ú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í.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.