-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Abhijit Sarkar
committed
Dec 22, 2024
1 parent
ce1f067
commit 045f097
Showing
6 changed files
with
130 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package ch07 | ||
|
||
/* | ||
We can use Semigroups and Monoids by importing two things: the type classes themselves, | ||
and the semigroup syntax to give us the |+| operator. | ||
*/ | ||
import cats.{Monoid as CatsMonoid} | ||
import cats.syntax.semigroup.catsSyntaxSemigroup | ||
|
||
object Lib: | ||
|
||
/* | ||
7.3.3.1 Exercise: Adding All The Things | ||
The cutting edge SuperAdder v3.5a-32 is the world's first choice for adding together numbers. | ||
The main function in the program has signature def add(items: List[Int]): Int. | ||
In a tragic accident this code is deleted! Rewrite the method and save the day! | ||
SuperAdder's market share continues to grow, and now there is demand for additional functionality. | ||
People now want to add List[Option[Int]]. Change add so this is possible. The SuperAdder code base | ||
is of the highest quality, so make sure there is no code duplication! | ||
*/ | ||
def add[A: CatsMonoid as m](items: List[A]): A = | ||
items.foldLeft(m.empty)(_ |+| _) | ||
|
||
// import cats.instances.int.catsKernelStdGroupForInt | ||
// add(List(1, 2, 3)) | ||
|
||
// add(List(Some(1), None, Some(2), None, Some(3))) | ||
|
||
// Doesn't compile: No given instance of type cats.kernel.Monoid[Some[Int]] was found. | ||
// The inferred type of the list is List[Some[Int]], Cats Monoid is invariant, so, | ||
// Monoid[Option[A]] is not applicable. | ||
// add(List(Some(1), Some(2), Some(3))) | ||
|
||
/* | ||
SuperAdder is entering the POS (point-of-sale, not the other POS) market. | ||
Now we want to add up Orders. | ||
We need to release this code really soon so we can’t make any modifications to add. | ||
Make it so! | ||
*/ | ||
case class Order(totalCost: Double, quantity: Double) | ||
|
||
given Monoid[Order]: | ||
def combine(o1: Order, o2: Order) = | ||
Order( | ||
o1.totalCost + o2.totalCost, | ||
o1.quantity + o2.quantity | ||
) | ||
|
||
def empty = Order(0, 0) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package ch07 | ||
|
||
trait Monoid[A] extends Semigroup[A]: | ||
def empty: A | ||
|
||
object Monoid: | ||
def apply[A : Monoid as m]: Monoid[A] = m | ||
|
||
/* | ||
7.2.0.1 Exercise: The Truth About Monoids | ||
Consider Boolean. How many monoids can you define for this type? | ||
*/ | ||
given booleanAndMonoid: Monoid[Boolean]: | ||
def combine(a: Boolean, b: Boolean) = a && b | ||
def empty = true | ||
|
||
given booleanOrMonoid: Monoid[Boolean]: | ||
def combine(a: Boolean, b: Boolean) = a || b | ||
def empty = false | ||
|
||
given booleanXorMonoid: Monoid[Boolean]: | ||
def combine(a: Boolean, b: Boolean) = | ||
a != b | ||
def empty = false | ||
|
||
// The negation of XOR | ||
given booleanXnorMonoid: Monoid[Boolean]: | ||
def combine(a: Boolean, b: Boolean) = | ||
(!a || b) && (a || !b) | ||
|
||
def empty = true | ||
|
||
/* | ||
7.2.0.2 Exercise: All Set for Monoids | ||
What monoids and semigroups are there for sets? | ||
*/ | ||
given setUnionMonoid: [A] => Monoid[Set[A]]: | ||
def combine(a: Set[A], b: Set[A]) = a.union(b) | ||
def empty = Set.empty[A] | ||
|
||
given symDiffMonoid: [A] => Monoid[Set[A]]: | ||
def combine(a: Set[A], b: Set[A]): Set[A] = | ||
(a.diff(b)).union(b.diff(a)) | ||
def empty: Set[A] = Set.empty |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package ch07 | ||
|
||
trait Semigroup[A]: | ||
def combine(x: A, y: A): A | ||
|
||
object Semigroup: | ||
// No identity element, can't form a Monoid. | ||
given setIntersectionSemigroup: [A] => Semigroup[Set[A]]: | ||
def combine(a: Set[A], b: Set[A]) = | ||
a.intersect(b) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package ch07 | ||
import org.scalatest.funspec.AnyFunSpec | ||
import org.scalatest.matchers.should.Matchers.shouldBe | ||
import ch07.Lib.add | ||
|
||
class LibSpec extends AnyFunSpec: | ||
describe("Monoid"): | ||
it("should add integers"): | ||
val ints = List(1, 2, 3) | ||
add(ints) `shouldBe` 6 | ||
|
||
it("should add strings"): | ||
val strings = List("Hi ", "there") | ||
add(strings) `shouldBe` "Hi there" | ||
|
||
it("should add sets"): | ||
val sets = List(Set("A", "B"), Set("B", "C")) | ||
add(sets) `shouldBe` Set("A", "B", "C") | ||
|
||
it("should add options"): | ||
val opts = List(Option(22), Option(20)) | ||
add(opts) `shouldBe` Option(42) |