////////// Exercice 1 ////////// // Maps a function `aFun` on a linked list `aList` function listMap(aList, aFun) { if (isEmpty(aList)) return aList; else return cons (aFun(head(aList)), listMap(tail(aList), aFun)); } const aSignedList = cons(5, cons(-5, cons(8, cons(-2, cons(14, nil))))); console.log(`Test listMap(${anyToString(aSignedList)}, Math.abs) : ` + `${anyToString(listMap(aSignedList, Math.abs))}`); // -> (|5,5,8,2,14|) // Computes the list of the squares of the list `aList` (supposed to // contain only numbers) function list2Squares(aList) { return listMap(aList, (x) => x*x); } console.log(`Test list2Squares(${anyToString(aSignedList)}) : ` + `${anyToString(list2Squares(aSignedList))}`); // -> (|25,25,64,4,196|) ////////// Exercice 2 ////////// import { listToString } from '#src/utils/list.functional.api.js'; // Fold a list from the left function listFoldL(aList, aFun, aInit) { if (isEmpty(aList)) return aInit; else return listFoldL(tail(aList), aFun, aFun(aInit, head(aList))); } function testListFoldL(aFun, aFunDisp, aInit, aList, anExpected) { const aResult = listFoldL(aList, aFun, aInit); const res = aResult === anExpected ? greenString('OK') : redString('KO'); console.log(`Test listFoldL(${aFunDisp}, ${aInit}, ${listToString()(aList)}) ` + `: ${res} (got ${aResult})`); } testListFoldL((acc, el) => acc+el, "add", 0, cons(3, cons(7, cons(10, nil))), 20); testListFoldL((acc, el) => acc-el, "sub", 0, cons(3, cons(7, cons(10, nil))), -20); // Fold a list from the right function listFoldR(aList, aFun, aInit) { if (isEmpty(aList)) return aInit; else { return aFun(listFoldR(tail(aList), aFun, aInit), head(aList)); } } function testListFoldR(aFun, aFunDisp, aInit, aList, anExpected) { const aResult = listFoldR(aList, aFun, aInit); const res = aResult === anExpected ? greenString('OK') : redString('KO'); console.log(`Test listFoldR(${aFunDisp}, ${aInit}, ${listToString()(aList)}) ` + `: ${res} (got ${aResult})`); } testListFoldR((acc, el) => acc+el, "add", 0, cons(3, cons(7, cons(10, nil))), 20); testListFoldR((acc, el) => acc-el, "sub", 0, cons(3, cons(7, cons(10, nil))), -20); ////////// Exercice 3 ////////// // Computes the product of the images of the elements of `aList` by `aFun` function listProdIterate(aFun, aList) { return listFoldR(aList, (acc, el) => aFun(el) * acc, 1); } const aList3 = cons(4, cons(9, cons(25, nil))); console.log(`Test listProdIterate(Math.sqrt, ${listToString()(aList3)}) : ` + `${listProdIterate(Math.sqrt, aList3)}`); // -> 30 // Reverses the elements of `aList` function listReverse(aList) { return listFoldL(aList, (acc, el) => cons(el, acc), nil); } console.log(`Test listReverse(${listToString()(aList)}) : ` + `${listToString()(listReverse(aList))}`); // -> (|14,-2,8,-5,5|) // Applies a map of `aFun` onto `aList` function listMapFold(aFun, aList) { return listFoldR(aList, (acc, el) => cons(aFun(el), acc), nil); } console.log(`Test listMapFold(double, ${listToString()(aList)}) : ` + `${listToString()(listMapFold((x) => 2*x, aList))}`); // -> (|10,-10,16,-4,28|) // Concatenates two lists `aList1` and `aList2` with a fold function listAppendFold(aList1, aList2) { return listFoldR(aList1, (acc, el) => cons(el, acc), aList2); } const aList2 = cons(1, cons(2, cons(3, cons(4, cons(5, nil))))); console.log(`Test listAppendFold(${listToString()(aList)}, ${listToString()(aList2)}}) : ` + `${listToString()(listAppendFold(aList, aList2))}`); // -> (|5,-5,8,-2,14,1,2,3,4,5|) // Count how many elements of the list `aList` match the predicate `aPred` function listHowMany (aPred, aList) { const yesOrNo = listMapFold((x) => {if (aPred(x)) return 1; else return 0;}, aList) return listFoldR(yesOrNo, (acc, el) => acc + el, 0); } console.log(`Test listHowMany(>5, ${listToString()(aList)}) : ` + `${listHowMany((x) => x > 5, aList)}`); // -> 2 ////////// Exercice 4 ////////// // Only if necessary import { listMap as safeListMap, listReduceRight as safeListFoldR } from '#src/utils/list.functional.higher.js'; // Map for two lists `aList1` and `aList2` of the same length and a // function `aFun` taking two params function listMapTwoParams(aFun, aList1, aList2) { if (isEmpty(aList1)) return aList1; else return cons(aFun(head(aList1), head(aList2)), listMapTwoParams(aFun, tail(aList1), tail(aList2))); } console.log(`Test listMapTwoParams(prod,${listToString()(aList3)},${listToString()(aList3)}) : ` + `${listToString()(listMapTwoParams((x,y) => x * y, aList3, aList3))}`); //(|16,81,625|) // Computes the scalar product of `aVector1` and `aVector2` (as linked // lists), assuming both vectors have the same length function listScalarProduct(aVector1, aVector2) { const prods = listMapTwoParams((x,y) => x * y, aVector1, aVector2); return listFoldR(prods, (acc, el) => acc + el, 0); } console.log(`Test listScalarProduct(${listToString()(aVector)},${listToString()(aVector)}) : ` + `${listScalarProduct(aVector, aVector)}`); // 14 // Computes the product matrix-vector function listMatVect(aMatrix, aVector) { return listMap(aMatrix, (line) => listScalarProduct(line, aVector)); } console.log(`Test listMatVect(${matrixToString()(aMatrix)},${listToString()(aVector)}) : ` + `${listToString()(listMatVect(aMatrix, aVector))}`); // Computes the transposition of the matrix `linesList` function listTranspose(linesList) { if (isEmpty(head(linesList))) // no more columns in the matrix return nil; else return cons(listMap(linesList, head), listTranspose (listMap(linesList, tail))); } console.log(`Test listTranspose(${matrixToString()(aMatrix)}) : ` + `${matrixToString()(listTranspose(aMatrix))}`); // Computes the product matrix-matrix function listMatMat(aMatrix1, aMatrix2) { return listTranspose(listMap(listTranspose(aMatrix2), (line) => listMatVect(aMatrix1, line))); } console.log(`Test listMatMat(${matrixToString()(aMatrix)}, ${matrixToString()(aMatrix)}) : ` + `${matrixToString()(listMatMat(aMatrix, aMatrix))}`);