From 81aa9d8ce684e877f127ae352ee11b173690622d Mon Sep 17 00:00:00 2001
From: "quentin.leblanc@etu.hesge.ch" <quentin.leblanc@etu.hesge.ch>
Date: Thu, 27 Feb 2020 17:41:42 +0100
Subject: [PATCH] TP 5

---
 TP3/src/main/scala/3.fp.scala         |  2 +-
 TP3/src/main/scala/4.lambda.scala     |  3 +-
 TP3/src/main/scala/5.hkfunc.scala     | 65 +++++++++++++++++++++++++++
 TP3/src/test/scala/4.lambdaTest.scala |  2 +
 TP3/src/test/scala/5.hkfuncTest.scala | 49 ++++++++++++++++++++
 5 files changed, 119 insertions(+), 2 deletions(-)
 create mode 100644 TP3/src/main/scala/5.hkfunc.scala
 create mode 100644 TP3/src/test/scala/5.hkfuncTest.scala

diff --git a/TP3/src/main/scala/3.fp.scala b/TP3/src/main/scala/3.fp.scala
index 2e89549..648b2e8 100644
--- a/TP3/src/main/scala/3.fp.scala
+++ b/TP3/src/main/scala/3.fp.scala
@@ -1,4 +1,4 @@
-
+package ch.hepia.scala
 /*
  * Implémenter les fonctions suivantes en suivant les commentaires.
  * Respectez également les consignes suivantes:
diff --git a/TP3/src/main/scala/4.lambda.scala b/TP3/src/main/scala/4.lambda.scala
index 3ad87fa..d4841c5 100644
--- a/TP3/src/main/scala/4.lambda.scala
+++ b/TP3/src/main/scala/4.lambda.scala
@@ -1,4 +1,5 @@
- /*
+package ch.hepia.scala
+/*
  * Implémenter les fonctions suivantes en suivant les commentaires.
  */
 
diff --git a/TP3/src/main/scala/5.hkfunc.scala b/TP3/src/main/scala/5.hkfunc.scala
new file mode 100644
index 0000000..d1c5164
--- /dev/null
+++ b/TP3/src/main/scala/5.hkfunc.scala
@@ -0,0 +1,65 @@
+package ch.hepia.scala
+
+/* Implémentez les fonctions suivantes. Vous ne pouvez utiliser que les
+ *  méthode de 'List' vues dans les exercices précédents.
+ */
+object HKFunc {
+
+  /* La fonction 'map' applique une fonction 'f' sur chaque élément de
+   * la liste 'as'.  La liste résultat doit avoir la même longueur que
+   * l'argument.
+   */
+  def map[A,B]( as: List[A] )( f: A=>B ): List[B] = {
+    @scala.annotation.tailrec
+    def applyOnHead(rec: List[A], acc: List[B]): List[B] = rec match {
+      case Nil => acc
+      case a :: tail => applyOnHead(tail, f(a)::acc)
+    }
+    Serie3.rev(applyOnHead(as, List.empty))
+  }
+
+  /* La fonction 'filter' utilise le prédicat 'f' pour déterminer quel
+   * élément garder. Le résultat peut être vide, mais l'ordre doit
+   * être préservé.
+bbb   */
+  def filter[A]( as: List[A] )( f: A=>Boolean ): List[A] = {
+    @scala.annotation.tailrec
+    def applyOnHead(rec: List[A], acc: List[A]): List[A] = rec match {
+      case Nil => acc
+      case a :: tail if f(a) => applyOnHead(tail, a::acc)
+      case a :: tail if !f(a) => applyOnHead(tail, acc)
+    }
+    Serie3.rev(applyOnHead(as, List.empty))
+  }
+
+  /* Réduit une liste 'as' en utilisant une opération binaire 'f'.  On
+   * supposera que 'as' n'est pas vide.
+   */
+  def reduce[A]( as: List[A] )( f: (A,A)=>A ): A = {
+    @scala.annotation.tailrec
+    def reduce2Head(rec: List[A], acc: A): A = rec match{
+      case Nil => acc
+      case b :: tail => reduce2Head(tail, f(b, acc))
+    }
+    reduce2Head(as.tail, as.head)
+  }
+
+
+
+
+
+  /* Transforme une fonction 'f' en une fonction s'appliquant sur une
+  *  liste. Utiliser la fonction 'map' définie ci-dessus
+  */
+  def lift[A,B]( f: A=>B ): List[A]=>List[B] = { (lstA: List[A]) => map(lstA)(f) }
+
+  /* DIFFICILE. Transforme une liste 'as' au moyen de la fonction 'f'.
+   * Cette fonction est appliquée à chaque élément de 'as' pour
+   * produire une nouvelle liste (qui peut être vide). Le résultat est
+   * la concaténation de chaque nouvelle liste en respectant l'ordre.
+   */
+  def bind[A,B]( as: List[A] )( f: A=>List[B] ): List[B] = {
+    Serie3.flat(map(as)(f))
+  }
+
+}
diff --git a/TP3/src/test/scala/4.lambdaTest.scala b/TP3/src/test/scala/4.lambdaTest.scala
index 3575b4c..ca18ce5 100644
--- a/TP3/src/test/scala/4.lambdaTest.scala
+++ b/TP3/src/test/scala/4.lambdaTest.scala
@@ -1,3 +1,5 @@
+package ch.hepia.scala
+
 import org.scalatest.funsuite.AnyFunSuite
 
 import Predicates._
diff --git a/TP3/src/test/scala/5.hkfuncTest.scala b/TP3/src/test/scala/5.hkfuncTest.scala
new file mode 100644
index 0000000..19641bb
--- /dev/null
+++ b/TP3/src/test/scala/5.hkfuncTest.scala
@@ -0,0 +1,49 @@
+package ch.hepia.scala
+
+
+import org.scalatest.funsuite.AnyFunSuite
+import HKFunc._
+
+class HKFunc5Suite extends AnyFunSuite {
+
+  val i0 = List[Int]()
+  val is = List( 1, 2, 3, 4 )
+
+  test("map") {
+    assert( map( i0 )(_ + 1 ) == i0 )
+    assert( map( is )(_ + 1 ) == List( 2, 3, 4, 5 ) )
+    assert( map( is )(_ * 2 ) == List( 2, 4, 6, 8 ) )
+  }
+
+  test("filter") {
+    assert( filter( i0 )(_ % 2 == 0 ) == i0 )
+    assert( filter( is )(_ % 2 == 0 ) == List( 2, 4 ) )
+  }
+
+  test("reduce") {
+    assert( reduce( is )( _ + _ ) == is.sum )
+    assert( reduce( is )( _ * _ ) == 24 )
+  }
+
+  test("lift") {
+    val f = (_:Int) + 1
+    val g = (_:Int) * 2
+    val id = lift[Int,Int]( identity )
+    assert( id(i0) == i0 )
+    assert( id(is) == is )
+    val h1 = lift( f andThen g )
+    val h2 = lift(f) andThen lift(g)
+    assert( h1(i0) == h2(i0) )
+    assert( h1(is) == h2(is) )
+  }
+
+  test("bind") {
+    val k = (i:Int) => if( i%2 == 0 ) List( -i, i ) else Nil
+    val l = (i:Int) => List( i, i )
+    assert( bind( i0 )( k ) == i0 )
+    assert( bind( is )( k ) == List( -2, 2, -4, 4 ) )
+    assert( bind( is )( l ) == List( 1, 1, 2, 2, 3, 3, 4, 4 ) )
+  }
+
+
+}
-- 
GitLab