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