From 6c5600f26ab348dbbf0f20e789bd28ca4d7ff725 Mon Sep 17 00:00:00 2001
From: Quentin <quentin.leblanc@etu.hesge.ch>
Date: Wed, 1 Apr 2020 15:54:15 +0200
Subject: [PATCH] serie 8

---
 TP3/build.sbt                           |   0
 TP3/src/main/scala/3.fp.scala           |   0
 TP3/src/main/scala/4.lambda.scala       |   0
 TP3/src/main/scala/5.hkfunc.scala       |   0
 TP3/src/main/scala/6.collect.scala      |   0
 TP3/src/main/scala/7.result.scala       |   0
 TP3/src/main/scala/8.monoids.scala      | 129 ++++++++++++++++++++++++
 TP3/src/test/scala/4.lambdaTest.scala   |   0
 TP3/src/test/scala/5.hkfuncTest.scala   |   0
 TP3/src/test/scala/6.collect_test.scala |   0
 TP3/src/test/scala/7.resultTest.scala   |   0
 TP3/src/test/scala/8.monoidTest.scala   |  63 ++++++++++++
 12 files changed, 192 insertions(+)
 mode change 100644 => 100755 TP3/build.sbt
 mode change 100644 => 100755 TP3/src/main/scala/3.fp.scala
 mode change 100644 => 100755 TP3/src/main/scala/4.lambda.scala
 mode change 100644 => 100755 TP3/src/main/scala/5.hkfunc.scala
 mode change 100644 => 100755 TP3/src/main/scala/6.collect.scala
 mode change 100644 => 100755 TP3/src/main/scala/7.result.scala
 create mode 100755 TP3/src/main/scala/8.monoids.scala
 mode change 100644 => 100755 TP3/src/test/scala/4.lambdaTest.scala
 mode change 100644 => 100755 TP3/src/test/scala/5.hkfuncTest.scala
 mode change 100644 => 100755 TP3/src/test/scala/6.collect_test.scala
 mode change 100644 => 100755 TP3/src/test/scala/7.resultTest.scala
 create mode 100755 TP3/src/test/scala/8.monoidTest.scala

diff --git a/TP3/build.sbt b/TP3/build.sbt
old mode 100644
new mode 100755
diff --git a/TP3/src/main/scala/3.fp.scala b/TP3/src/main/scala/3.fp.scala
old mode 100644
new mode 100755
diff --git a/TP3/src/main/scala/4.lambda.scala b/TP3/src/main/scala/4.lambda.scala
old mode 100644
new mode 100755
diff --git a/TP3/src/main/scala/5.hkfunc.scala b/TP3/src/main/scala/5.hkfunc.scala
old mode 100644
new mode 100755
diff --git a/TP3/src/main/scala/6.collect.scala b/TP3/src/main/scala/6.collect.scala
old mode 100644
new mode 100755
diff --git a/TP3/src/main/scala/7.result.scala b/TP3/src/main/scala/7.result.scala
old mode 100644
new mode 100755
diff --git a/TP3/src/main/scala/8.monoids.scala b/TP3/src/main/scala/8.monoids.scala
new file mode 100755
index 0000000..e2a4744
--- /dev/null
+++ b/TP3/src/main/scala/8.monoids.scala
@@ -0,0 +1,129 @@
+package ch.hepia.tpscala.monoid
+
+import ch.hepia.tpscala.monoid
+
+trait Monoid[A] {
+  def op( a1: A, a2: A ): A
+  def zero: A
+}
+
+object Monoid {
+  def apply[A]( z: A )( f: (A,A)=>A ) = new Monoid[A] {
+    def op( a1: A, a2: A ): A = f(a1,a2)
+    def zero: A = z
+  }
+
+  object Laws {
+    def checkAssociativity[A](
+      mon: Monoid[A], a1: A, a2: A, a3: A
+    ) = {
+      import mon.op
+      op(a1,op(a2,a3)) == op(op(a1,a2),a3)
+    }
+    def checkNeutral[A](
+      mon: Monoid[A], a: A
+    ) = {
+      import mon._
+      op(zero,a) == a && op(a,zero) == a
+    }
+  }
+}
+
+object Monoids {
+
+  val intSum = Monoid(0)( _ + _ )
+  val intProd = Monoid(1)( _ * _ )
+
+  val doubleSum = Monoid( 0.0 )( _ + _ )
+  val doubleMax = Monoid( Double.MinValue )( _ max _ )
+  val doubleMin = Monoid( Double.MaxValue )( _ min _ )
+
+  def listFlat[A] = Monoid[List[A]]( Nil )( _ ++ _ )
+
+  def setUnion[A] = Monoid( Set.empty[A] )( _ ++ _ )
+
+  def pipeline[A] = Monoid[A=>A]( identity )( _ andThen _ )
+
+  def optionM[A]( op: (A,A)=>A ) =
+    Monoid[Option[A]]( None ){ (lhs,rhs) =>
+      (lhs,rhs) match {
+        case (None,_) => rhs
+        case (_,None) => lhs
+        case (Some(a),Some(b)) => Some( op(a,b) )
+      }
+    }
+
+  val optIntProd = optionM( intProd.op )
+  val optDoubleMax = optionM( doubleMax.op )
+
+
+  def tuple2M[A,B]( MA: Monoid[A], MB: Monoid[B] ) =
+    Monoid[(A,B)]( (MA.zero,MB.zero) ){ (ab1,ab2) =>
+      ( MA.op( ab1._1, ab2._1 ), MB.op( ab1._2, ab2._2 ) )
+    }
+
+
+  def mapM[K,V]( M: Monoid[V] ) = {
+    def merge( lhs: Map[K,V], rhs: Map[K,V] ): Map[K,V] = {
+      val ks = lhs.keySet ++ rhs.keySet
+      ks.map{ k =>
+        val v = M.op(
+          lhs.getOrElse(k,M.zero),
+          rhs.getOrElse(k,M.zero) )
+        k -> v
+      }.toMap
+    }
+    Monoid[Map[K,V]]( Map() )( merge )
+  }
+}
+
+object Examples {
+
+  import Monoids._
+
+  def mapReduce[A,B]( as: List[A] )(f: A=>B, M: Monoid[B]): B = {
+    def rec( rem: List[A], acc: B ): B = rem match {
+      case Nil => acc
+      case h :: t => rec( t, M.op(acc, f(h) ) )
+    }
+    rec( as, M.zero )
+  }
+  def reduce[A]( as: List[A] )( M: Monoid[A] ): A =
+    mapReduce( as )( identity, M )
+
+  //Donné à titre d'exemple
+  def averageM[A]( MA: Monoid[A] ): Monoid[(A,Int)] =
+    tuple2M( MA, intSum )
+  val avgDouble = averageM( doubleSum )
+  def average( as: List[Double] ): Option[Double] =
+    if( as.isEmpty ) None
+    else {
+      val (sum,n) =
+        mapReduce( as )( a => (a,1), avgDouble )
+      Some( sum/n )
+    }
+
+
+  //Série 3: and
+  def and( xs: List[Boolean] ): Boolean = reduce(xs)(Monoid[Boolean](true)(_ && _))
+
+  //Retourne le min et le max d'une liste de doubles en un seul parcours
+  def minMax( as: List[Double] ): (Double,Double) = mapReduce[Double, (Double, Double)](as)((a:Double) => (a, a), tuple2M(doubleMin, doubleMax))
+
+  //Série 3: Even
+  def even[A]( as: List[A] ): Boolean = mapReduce[A, Int](as)(_ => 1, intSum)%2 == 0
+
+  //Compte le nombre d'occurence de chaque objet de la liste
+  def count[A]( as: List[A] ): Map[A,Int] = mapReduce[A, Map[A, Int]](as)((x: A) => Map[A, Int](x -> 1), mapM[A, Int](Monoid[Int](0)(_ + _)))
+
+  //Compte le nombre d'occurence de chaque pair d'objet
+  def count2[A,B]( as: List[(A,B)] ): Map[A,Map[B,Int]] = mapReduce[(A,B), Map[A,Map[B, Int]]](as)( (x:(A,B)) => Map(x._1 -> Map(x._2 -> 1)),mapM[A,Map[B, Int]](mapM[B, Int](Monoid[Int](0)(_ + _))))
+
+  //Série 4: forall
+  def forall[A]( ps: List[(A)=>Boolean] ): (A)=>Boolean = (a:A) => { mapReduce(ps)((p:A=>Boolean) => p(a), Monoid[Boolean](true)(_ && _)) }
+
+
+}
+
+
+
diff --git a/TP3/src/test/scala/4.lambdaTest.scala b/TP3/src/test/scala/4.lambdaTest.scala
old mode 100644
new mode 100755
diff --git a/TP3/src/test/scala/5.hkfuncTest.scala b/TP3/src/test/scala/5.hkfuncTest.scala
old mode 100644
new mode 100755
diff --git a/TP3/src/test/scala/6.collect_test.scala b/TP3/src/test/scala/6.collect_test.scala
old mode 100644
new mode 100755
diff --git a/TP3/src/test/scala/7.resultTest.scala b/TP3/src/test/scala/7.resultTest.scala
old mode 100644
new mode 100755
diff --git a/TP3/src/test/scala/8.monoidTest.scala b/TP3/src/test/scala/8.monoidTest.scala
new file mode 100755
index 0000000..736232e
--- /dev/null
+++ b/TP3/src/test/scala/8.monoidTest.scala
@@ -0,0 +1,63 @@
+package ch.hepia.tpscala.monoid
+
+import org.scalatest.funsuite.AnyFunSuite
+
+import Examples._
+
+class Monoid8Suite extends AnyFunSuite {
+
+
+  test( "minMax" ) {
+    assert( minMax( List(1,2,3,4,5,6) ) == (1,6)  )
+    assert( minMax( List(1) ) == (1,1)  )
+    assert( minMax( List(2,2,2,2,2,2,2,2) ) == (2,2) )
+    assert( minMax( List(100,-100) ) == (-100, 100) )
+  }
+
+  test( "and" ) {
+    assert( and(Nil) && and(List(true)) == true )
+    assert( and(List( true, true, true ))  == true )
+    assert( and(List( true, true, false ))  == false )
+  }
+
+  test( "even" ) {
+    assert( even( Nil ) == true )
+    assert( even( List(0) ) == false )
+    assert( even( List(0,0) ) == true )
+    assert( even( List(0,0,0) ) == false )
+    assert( even( List(0,0,0,0) ) == true )
+    assert( even( List(0,0,0,0,0) ) == false )
+  }
+
+
+  test( "count" ) {
+    assert( count( List("y", "n", "y", "y", "n", "y") ) == Map( "y"->4, "n"->2 ) )
+    assert( count(Nil) == Map() )
+    assert( count( List(1,2,3,4,5) ) == Map( 1->1, 2->1, 3->1, 4->1, 5->1 ) )
+  }
+
+  test( "count2" ) {
+    assert(
+      count2( List( ("a","y"), ("a", "y"), ("b","y"), ("b","n"), ("c","y") ) ) ==
+        Map(
+          "a" -> Map("y"->2),
+          "b" -> Map ("y"->1, "n"->1),
+          "c" -> Map("y"->1 )
+        )
+    )     
+  }
+
+  test( "forall" ) {
+    val big = (_:Int) >= 100
+    val even = (_:Int) % 2 == 0
+    val mul3 = (_:Int ) % 3 == 0
+    val ps = forall( List( big, even, mul3 ) )
+    assert( ps( 402 ) )
+    assert( ! ps( 200 ) )
+    assert( forall( Nil )( 402 ) )
+    assert( forall( Nil )( 200 ) )
+  }
+
+
+
+}
-- 
GitLab