# Functional Programming > Concept & Example --- ### Pure functions ### Function Composition ### Avoid shared/mutating state ### Avoid side effects --- ## Pure Function > ƒ(x) = x ---- ![](https://i.imgur.com/FkUpkZm.png =x400) ---- ![](https://i.imgur.com/8S7lE2l.png) ```javascript= const toFahrenheit = celcius => celcius * 9/5 + 32 ``` --- ## Function Composition > ƒ( g(x) ) ---- ![](https://i.imgur.com/rPa2Xfc.png =x500) ---- ### Composition ```javascript= const f = x => Math.pow(x, 2) const g = x => x + 1 const gComposeF = R.compose(g, f) gComposeF(3) // 10 ``` ---- ### Pipe ```javascript= const f = x => Math.pow(x, 2) const g = x => x + 1 const fThenG = R.pipe(f, g) fThenG(3) // 10 ``` --- ## Avoid shared/mutating state > Subtle bug ```javascript= const list = [1,2,3,3,4,5]; for (var i = 0; i < list.length; ++i) { if (list[i] === 3) { list.splice(i, 1); } } console.log(list); // [1,2,3,4,5] ``` ---- ```javascript= const list = [1,2,3,3,4,5]; console.log( list.filter(item => item !== 3) ); // [1,2,4,5] console.log(list); //[1,2,3,3,4,5] ``` --- ## Avoid side effect - Generally, avoid IO operation in functions. - In JavaScript: Decompose complex functions into pure functions. - Application without side effect is probably useless. --- ### Different Ways on FP (and managing side effect) - FP design patterns - Algebraic structures like Monads/Monoids/Functor/others - Pattern Matching - Reactive functional programming --- ### Algebraic Data Structure - Details: - JS ??? - FP languages: OCaml/Elixir/Scala/Elm/PureScript ---- ### "Common" Algebraic Data Types ![](https://i.imgur.com/nEd1sTr.png) [Functor](https://github.com/fantasyland/fantasy-land#functor) • [Applicative](https://github.com/fantasyland/fantasy-land#applicative) • [Monad](https://github.com/fantasyland/fantasy-land#monad) --- ### Cut to the chase... Example use case: - Calculate the temperature reading in Farenheit from a single thermometer probe, after 20ºC temperature increment. - Similar to above, but for a grouped reading from thermometers from different locations, by taking the average reading. ---- ```scala= def convertCelciusToFarenheit(celcius: Double) = celcius * 9/5 + 32 def increaseTemp(increment: Double, initial: Double) = initial + increment def increaseTempBy20 = increaseTemp(20, _: Double) def sum(numbers: Seq[Double]) = numbers.reduce(_ + _) def mean(numbers: Seq[Double]) = sum(numbers) / numbers.length ``` ---- ```scala= Option(potentiallyNullTemperature) .map(increaseTemperatureBy20) .map(convertCelciusToFarenheit) // => Some(number) // => None (if `potentiallyNullTemperature` is null) val probesTemperatureInCelcius = Map( "location1" -> List(23.3, 45.2, 23.4), "location2" -> List(24.9) ) probesTemperatureInCelcius.values.flatten .map(increaseTemperatureBy20) .map(convertCelciusToFarenheit) // => List(23.3, 45.2, 23.4, 24.9) ``` ---- ### Algebraic Operation Ecosystem In JavaScript - [fantasy-land](https://github.com/fantasyland/fantasy-land) specs ❓ - [ramda](https://ramdajs.com/) 👍🏼 ---- #### Functional Programming in JS Modified example from https://fr.umio.us/favoring-curry/ (plain JS): ```javascript= const getIncompleteTaskSummaries = function(membername) { return fetchData() .then(({tasks}) => tasks) .then(tasks => tasks.filter( ({username}) => membername) ) .then(tasks => tasks.filter( ({complete}) => !complete) ) .then(tasks => tasks.map( ({id, dueDate, title, priority}) => ({id, dueDate, title, priority}) )) .then(abbreviatedTasks => abbreviatedTasks.sort(({dueDate}) => dueDate) ); }; ``` ---- For readability and testability: ```javascript= const extractUsername = (membername) => tasks => tasks.filter(({username}) => membername) const notComplete = tasks => tasks.filter(({complete}) => !complete) const extractImportantAttributes = tasks => tasks.map( ({id, dueDate, title, priority}) => ({id, dueDate, title, priority}) ) const sortByDueDate = abbreviatedTasks => abbreviatedTasks.sort(({dueDate}) => dueDate) const getIncompleteTaskSummaries = function(membername) { return fetchData() .then(({tasks}) => tasks) .then(extractUsername(membername)) .then(notComplete) .then(extractImportantAttributes) .then(sortByDueDate) }; ``` ---- Ramda equivalent: ```javascript= var getIncompleteTaskSummaries = function(membername) { return fetchData() .then(R.get('tasks')) .then(R.filter(R.propEq('username', membername))) .then(R.reject(R.propEq('complete', true))) .then(R.map(R.pick( ['id', 'dueDate', 'title', 'priority'] ))) .then(R.sortBy(R.get('dueDate'))); }; ``` ---- #### Scala ```scala= case class Task( ... ) case class Response(task: Task) val fetchData: Future[Response] = Future { ... } fetchData .map(_.task) .filter(_.username == membername) .filterNot(_.complete == true) .map(TaskDto( id = _.id, dueDate = _.dueDate, title = _.title, priority = _.priority )) .sortBy(_.dueDate) ``` > FP-style: Work with the "box" safely. --- ## Pattern Matching ```scala= case class TaskDto(id: Long, dueDate: Date, title: String, priority: Priority) val aTaskDto: Option[TaskDto] = _ aTaskDto match { case Some(TaskDto(_, _, _, priority)) if priotity == Priority.High => escalatedProcessing() case Some(TaskDto(_, dueDate, _, _)) if dueDate.after(DueDate) => prioritisedProcessing() case Some(TaskDto) => normalTaskProcessing() case _ => doNothing() } ``` ---- #### Reusability and testability ```scala= val wayToProcessTheTask = { case Some(TaskDto(_, _, _, priority)) if priotity == Priority.High => escalatedProcessing() case Some(TaskDto(_, dueDate, _, _)) if dueDate.after(DueDate) => prioritisedProcessing() case Some(TaskDto) => normalTaskProcessing() case _ => doNothing() } // this is a partial function val taskDtos: List[TaskDto] = _ taskDtos.map(wayToProcessTheTask) ``` --- ## Reactive functional programming ![](https://i.imgur.com/UKuS3JJ.png) ---- Examples: - [ReactiveX](http://reactivex.io/): Async programming with observable stream - RxJS, RxScala, RxJava - Spring 5 no longer MVC, but reactive using Java stream. - In data processing categories: akka-stream / Apache Spark streams / Apache Flink - On the UI: https://cycle.js.org/ ---- Why "reactive **functional** programming"? > Discussion > --- Q&As
{"metaMigratedAt":"2023-06-14T18:37:40.323Z","metaMigratedFrom":"Content","title":"Functional Programming","breaks":true,"contributors":"[{\"id\":\"b0d38937-48da-4a45-8f43-2ae9039a2c07\",\"add\":9281,\"del\":2478}]"}
    2233 views