From d8643d22247dcabd39224aea8b88a30be0a66fc1 Mon Sep 17 00:00:00 2001
From: "joel.vonderwe" <joel.von-der-weid@etu.hesge.ch>
Date: Thu, 27 Feb 2020 15:27:23 +0100
Subject: [PATCH] HK functions

---
 base_tp/src/hkfunc/hkfunc.scala | 73 +++++++++++++++++++++++++++++++++
 base_tp/test/hkfuncTest.scala   | 49 ++++++++++++++++++++++
 2 files changed, 122 insertions(+)
 create mode 100644 base_tp/src/hkfunc/hkfunc.scala
 create mode 100644 base_tp/test/hkfuncTest.scala

diff --git a/base_tp/src/hkfunc/hkfunc.scala b/base_tp/src/hkfunc/hkfunc.scala
new file mode 100644
index 0000000..fdbceef
--- /dev/null
+++ b/base_tp/src/hkfunc/hkfunc.scala
@@ -0,0 +1,73 @@
+package ch.hepia.tpscala
+
+/* 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] = {
+    def mapRec(as: List[A], news : List[B]) : List[B] = {
+        as match {
+            case Nil => news.reverse
+            case a :: rest => mapRec(rest, f(a) :: news)
+        }
+    }
+    mapRec(as, Nil)
+  }
+
+  /* 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é.
+   */
+  def filter[A]( as: List[A] )( f: A=>Boolean ): List[A] = {
+    def filterRec(as: List[A], news : List[A]): List[A] = {
+        as match {
+            case Nil => news.reverse
+            case a :: rest if f(a) => filterRec(rest, a :: news)
+            case _ :: rest => filterRec(rest, news)
+        }
+    }
+    filterRec(as, Nil)
+  }
+
+  /* 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 = {
+      def reduceRec(as: List[A], acc : A): A = {
+        as match {
+            case Nil => acc
+            case a :: rest => reduceRec(rest, f(acc, a))
+        }
+    }
+    reduceRec(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] = {
+      (as: List[A]) => {
+          map(as)(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] = {
+    def bindRec(as: List[A], bs: List[B]): List[B] = {
+      as match {
+        case Nil => bs
+        case a :: rest => bindRec(rest, bs ++ f(a))
+      }
+    }
+    bindRec(as, Nil)
+  }
+}
diff --git a/base_tp/test/hkfuncTest.scala b/base_tp/test/hkfuncTest.scala
new file mode 100644
index 0000000..4e6e26b
--- /dev/null
+++ b/base_tp/test/hkfuncTest.scala
@@ -0,0 +1,49 @@
+package ch.hepia.tpscala
+
+
+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