Concept & Example
ƒ(x) = x
const toFahrenheit = celcius => celcius * 9/5 + 32
ƒ( g(x) )
const f = x => Math.pow(x, 2) const g = x => x + 1 const gComposeF = R.compose(g, f) gComposeF(3) // 10
const f = x => Math.pow(x, 2) const g = x => x + 1 const fThenG = R.pipe(f, g) fThenG(3) // 10
Subtle bug
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]
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]
Example use case:
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
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)
Modified example from https://fr.umio.us/favoring-curry/ (plain JS):
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:
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:
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'))); };
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.
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() }
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)
Examples:
Why "reactive functional programming"?
Discussion
Q&As