Functional Programming presentation

· tulkdan's blog


Table of Contents #

  1. Functional Programming
  2. Functional Programming
    1. What it is
    2. Little bit of history
    3. Changing of paradigms of programming languages
  3. Concepts of functional programming
    1. Everything is a function
    2. Declarative code
      1. Examples
    3. Immutability
      1. Examples
    4. Lazy evaluation
      1. Examples
    5. Recursion
      1. Example
    6. Pure functions
      1. Examples
    7. High-order functions
      1. Example
  4. Function composition
    1. Pipe
      1. Examples
    2. Compose
    3. Curry
      1. Examples
  5. Downsides
  6. References

Functional Programming #

img

Functional Programming #

What it is #

Little bit of history #

Changing of paradigms of programming languages #

Concepts of functional programming #

Everything is a function #

Declarative code #

What's de diference between these methods in JS?

We could implement all these methods with a for loop or the forEach() method, they all seem so redundant…

Examples #

  1. Imperative

    const dataModified = [
        { name: 'bar', value: 100 },
        { name: 'bar', value: 101 }
    ]
    
    for (const item of dataModified) {
        item.id = `${item.name}-${item.value}`
    }
    
    console.log(dataModified)
    
  2. Functional

    const dataModified = [
        { name: 'bar', value: 100 },
        { name: 'bar', value: 101 }
    ]
    
    const result = dataModified.map(item => ({
        ...item,
        id: `${item.name}-${item.value}`
    }))
    
    console.log(result)
    

Immutability #

Examples #

  1. With side effects

    const proPlayer = {
        name: 'Flash',
        game: 'Starcraft: Brood War',
        race: 'Terran',
        matches: { wins: 779, losses: 297 }
    }
    
    function winRate(player) {
        return new Promise(resolve => {
            setTimeout(() => {
                const games = player.matches.wins + player.matches.losses
                const winRate = player.matches.wins / games
                console.log(`Player ${player.name} has a win rate of ${winRate * 100}`)
                resolve()
            }, 200)
        })
    }
    
    function lostMatch(player) {
        return new Promise(resolve => {
            setTimeout(() => {
                console.log('Player has lost a match')
                player.matches.losses += 1
                resolve()
            }, 100)
        })
    }
    
    
    winRate(proPlayer)
        .then(() => Promise.all([
            winRate(proPlayer),
            lostMatch(proPlayer),
        ]))
    
  2. With Immutability

    const proPlayer = {
        name: 'Flash',
        game: 'Starcraft: Brood War',
        race: 'Terran',
        matches: { wins: 779, losses: 297 }
    }
    
    function winRate(player) {
        return new Promise(resolve => {
            setTimeout(() => {
                const games = player.matches.wins + player.matches.losses
                const winRate = player.matches.wins / games
                console.log(`Player ${player.name} has a win rate of ${winRate * 100}`)
                resolve()
            }, 200)
        })
    }
    
    function lostMatch(player) {
        return new Promise(resolve => {
            setTimeout(() => {
                console.log('Player has lost a match')
                const newData = {
                    ...player,
                    matches: { ...player.matches, losses: player.matches.losses + 1 }
                }
                resolve(newData)
            }, 100)
        })
    }
    
    winRate(proPlayer)
        .then(() => Promise.all([
            winRate(proPlayer),
            lostMatch(proPlayer),
        ]))
    

Lazy evaluation #

Examples #

const rand = function * () {
    while (true) {
        yield Math.random()
    }
}

const randIter = rand()
console.log(randIter.next())
console.log(randIter.next())
console.log(randIter.next())

Recursion #

See Sergio's presentation about it

Example #

function factorial(number) {
    if (number === 0) return 1
    return number * factorial(number - 1)
}

console.log(factorial(3))

Pure functions #

Examples #

  1. Impure

    const newBand = {
        name: 'Black Country, New Road',
        members: ['Tyler', 'Lewis', 'Georgia', 'May', 'Charlie', 'Luke', 'Isaac'],
        albums: ['Ants from Up There']
    }
    
    const newBand = {
        name: 'Black Country, New Road',
        members: ['Tyler', 'Lewis', 'Georgia', 'May', 'Charlie', 'Luke', 'Isaac'],
        albums: ['Ants from Up There']
    }
    
    function releaseRecord(recordName) {
        newBand.albums.push(recordName)
    }
    
    function removeMember(memberName) {
        const index = newBand.members.indexOf(memberName)
        newBand.members.splice(index, 1)
    }
    
    removeMember('Isaac')
    
    console.log(newBand)
    
    releaseRecord('Live at Bush Hall')
    
    console.log(newBand)
    
  2. Pure

    const newBand = {
        name: 'Black Country, New Road',
        members: ['Tyler', 'Lewis', 'Georgia', 'May', 'Charlie', 'Luke', 'Isaac'],
        albums: ['Ants from Up There']
    }
    
    const releaseRecord = (band, recordName) => ({
        ...band,
        albums: [...band.albums, recordName]
    })
    
    const removeMember = (band, memberName) => ({
        ...band,
        members: band.members.filter(member => member !== memberName)
    })
    
    const bandWithoutIsaac = removeMember(newBand, 'Isaac')
    
    console.log(bandWithoutIsaac)
    
    const bandWithANewRecord = releaseRecord(bandWithoutIsaac, 'Live at Bush Hall')
    
    console.log(newBand)
    console.log(bandWithANewRecord)
    

High-order functions #

See Vandre's presentation about closure

Example #

const kingGizzard = {
    name: 'King Gizzard and the Lizard Wizard',
    genres: [
        'garage rock',
        'rock',
        'psychedelic rock',
        'jazz fusion',
        'heavy psychedelic rock',
        'progressive rock',
        'syth pop',
        'thrash metal'
    ]
}

const kingGizzard = {
    name: 'King Gizzard and the Lizard Wizard',
    genres: [
        'garage rock',
        'rock',
        'psychedelic rock',
        'jazz fusion',
        'heavy psychedelic rock',
        'progressive rock',
        'syth pop',
        'thrash metal'
    ]
}
function validateBandGenre(band) {
    return function(genre) {
        return band.genres.includes(genre)
    }
}

// or using arrow function ===> const validateBandGenre = band => genre => band.genres.includes(genre)

const validateKingGizzardGenres = validateBandGenre(kingGizzard)

console.log(
    validateKingGizzardGenres('rock')
)
console.log(
    validateKingGizzardGenres('pop')
)

Function composition #

Pipe #

Examples #

  1. Without pipe

    const newBand = {
        name: 'Black Country, New Road',
        members: ['Tyler', 'Lewis', 'Georgia', 'May', 'Charlie', 'Luke', 'Isaac'],
        albums: ['Ants from Up There']
    }
    
    const releaseRecord = recordName => band => ({
        ...band,
        albums: [...band.albums, recordName]
    })
    
    const removeMember = memberName => band => ({
        ...band,
        members: band.members.filter(member => member !== memberName)
    })
    
    const bandWithoutIsaac = removeMember('Isaac')(newBand)
    
    console.log(bandWithoutIsaac)
    
    const bandWithANewRecord = releaseRecord('Live at Bush Hall')(bandWithoutIsaac)
    
    console.log(newBand)
    console.log(bandWithANewRecord)
    
  2. With pipe

    function pipe(...fns) {
        return function(value) {
            return fns.reduce((acc, fn) => fn(acc), value)
        }
    }
    const newBand = {
        name: 'Black Country, New Road',
        members: ['Tyler', 'Lewis', 'Georgia', 'May', 'Charlie', 'Luke', 'Isaac'],
        albums: ['Ants from Up There']
    }
    
    const releaseRecord = recordName => band => ({
        ...band,
        albums: [...band.albums, recordName]
    })
    
    const removeMember = memberName => band => ({
        ...band,
        members: band.members.filter(member => member !== memberName)
    })
    
    const finalLineup = pipe(removeMember('Isaac'), releaseRecord('Live at Bush Hall'))
    
    console.log(
        finalLineup(newBand)
    )
    

Compose #

Curry #

Examples #

  1. Without curry

    const kingGizzard = {
        name: 'King Gizzard and the Lizard Wizard',
        genres: [
            'garage rock',
            'rock',
            'psychedelic rock',
            'jazz fusion',
            'heavy psychedelic rock',
            'progressive rock',
            'syth pop',
            'thrash metal'
        ]
    }
    
    function validateBand(band, field, data) {
        if (field === 'name') {
            return band.name === data
        }
    
        if (field === 'genres') {
            return band.genres.includes(data)
        }
    }
    
    console.log(
        validateBand(kingGizzard, 'genres', 'rock')
    )
    console.log(
        validateBand(kingGizzard, 'genres', 'psychedelic rock')
    )
    
  2. With curry

    const kingGizzard = {
        name: 'King Gizzard and the Lizard Wizard',
        genres: [
            'garage rock',
            'rock',
            'psychedelic rock',
            'jazz fusion',
            'heavy psychedelic rock',
            'progressive rock',
            'syth pop',
            'thrash metal'
        ]
    }
    function curry(fn, arity) {
        arity ||= fn.length
    
        return function(...args) {
            if (args.length < arity) {
                return curry(
                    (...lefts) => fn(...args, ...lefts),
                    arity - args.length
                )
            }
    
            return fn(...args)
        }
    }
    
    function validateBand(band, field, data) {
        if (field === 'name') {
            return band.name === data
        }
    
        if (field === 'genres') {
            return band.genres.includes(data)
        }
    }
    
    const curriedValidateBand = curry(validateBand)
    
    const validateKingGizzardGenres = curriedValidateBand(kingGizzard, 'genres')
    
    console.log(
        validateKingGizzardGenres('rock')
    )
    console.log(
        validateKingGizzardGenres('psychedelic rock')
    )
    

Downsides #

References #