Dear Functional Bros

CodeAesthetic
23 Dec 202316:50

Summary

TLDRThe script discusses the beauty and challenges of functional programming, emphasizing its pure concept of stateless functions and the avoidance of side effects. It explains how functional programming deals with loops and state management through recursion and functions, introducing concepts like currying and lambda functions. The video also demonstrates how functional principles can be applied in JavaScript to create efficient data pipelines, transforming and filtering data in a more declarative manner. The speaker encourages a balanced approach, adopting functional concepts where beneficial without the strict limitations of pure functional programming.

Takeaways

  • 📚 Functional programming emphasizes pure functions with no side effects, ensuring the same output for the same input.
  • 🔍 Functional programmers often struggle with marketing their concepts due to the complex terminology like currying, monads, and functors.
  • 🔗 Composing functions by connecting their inputs and outputs is a core concept in functional programming, avoiding stateful objects and mutation.
  • ✅ Pure functional programming does not allow mutation of variables, making conventional loops like for and while impossible.
  • 🔄 Recursion is used in functional programming as a form of iteration, allowing for loops to be expressed as function calls.
  • 🔢 The script demonstrates converting a for loop into a series of functional programming constructs like higher-order functions and recursion.
  • 🔍 Filtering, mapping, and taking elements from a list are common functional programming operations that can replace traditional loops.
  • 📝 Currying allows for the creation of specialized functions by partially applying arguments, which is useful for creating reusable code patterns.
  • 🌐 Functional programming principles have been integrated into popular languages like JavaScript, making it easier to create data pipelines and handle complex operations.
  • 🚀 Adopting functional programming principles can lead to more concise and readable code, especially when dealing with data transformations and manipulations.
  • 🌟 While pure functional programming has its limitations, its best practices can be applied selectively to improve code quality and efficiency.

Q & A

  • What is the core concept of functional programming?

    -The core concept of functional programming is to write programs with no state, meaning there are no side effects, and the same input always produces the same output.

  • Why are functional programmers considered bad marketers?

    -Functional programmers may be considered bad marketers because they often use complex terms like currying, monads, and functors, which can be difficult for non-experts to understand.

  • How does functional programming handle loops without using conventional iteration constructs like 'for' or 'while'?

    -Functional programming handles loops using recursion and functions, which are designed to perform a specific task repeatedly without mutating state.

  • What is the purpose of currying in functional programming?

    -Currying is a technique in functional programming where a function that takes multiple arguments is transformed into a sequence of functions, each with a single argument. This allows for more flexible and reusable functions.

  • How does the script demonstrate the use of a 'filter' function in functional programming?

    -The script demonstrates the 'filter' function by showing how to pass a predicate (a condition-checking function) to filter elements from a list based on a condition, such as matching a user ID.

  • What is the 'map' function used for in functional programming?

    -The 'map' function is used to transform each element of a list according to a given function, creating a new list with the transformed elements.

  • How does the script illustrate the creation of a data pipeline in functional programming?

    -The script illustrates a data pipeline by chaining together operations such as filtering, mapping, and taking a certain number of elements, which allows for a clear declaration of desired outcomes and simplifies the complexity behind the scenes.

  • The startup idea aims to address the issue of credit card fraud in restaurants, where the tip and total amounts are manually entered and may not accurately reflect the customer's intention, potentially leading to overcharges.

    -null

  • How does the script suggest functional programming can be beneficial in data-centric jobs?

    -The script suggests that functional programming can simplify data-centric jobs by allowing programmers to focus on transforming, filtering, and sorting data in a clear and concise manner, acting as 'sophisticated plumbers' to manage data flows effectively.

  • What is the script's stance on pure functional programming?

    -The script acknowledges that pure functional programming, which prohibits state mutation and side effects, is mostly academic and not practical for real-world computing. However, it highlights that adopting some functional principles can bring significant benefits without the restrictive nature of pure functional programming.

Outlines

00:00

📚 Introduction to Functional Programming

The paragraph discusses the beauty of functional programming, emphasizing the purity of functions that take inputs and produce outputs without side effects or state. It highlights the challenge of marketing functional programming concepts like currying, monads, and functors, which are complex and lie between mathematical theories and practical language implementations. The speaker acknowledges the difficulty in understanding these concepts but appreciates their elegance. The paragraph also touches on the core concept of functional programming, which is the absence of state, and how this affects common programming constructs like loops and mutation of variables. It introduces the idea of using functions to manage state and the use of recursion as a form of iteration in functional programming.

05:02

🔄 Functional Loops and Currying

This paragraph delves into the specifics of implementing loops in a functional programming paradigm. It explains how to convert a for loop into a series of function calls, using recursion and conditions to mimic the loop's behavior. The speaker introduces the concept of currying, where a function is partially applied by fixing some of its arguments, allowing for more flexible and reusable code. The paragraph also discusses the use of higher-order functions like filter and map, which take other functions as arguments to perform operations on data, and how these can be used to create data pipelines for processing and transforming information.

10:02

🚀 Applying Functional Concepts in JavaScript

The speaker transitions from theoretical concepts to practical applications, showing how functional programming principles can be applied in JavaScript. They demonstrate how to use built-in array methods like map, filter, and sort to create data pipelines that transform and process data. The paragraph also presents a real-world scenario involving a startup that aims to prevent credit card fraud by analyzing restaurant receipts and transactions. The speaker rewrites procedural code into a functional style, showcasing the elegance and efficiency of the functional approach.

15:02

🌟 The Future of Functional Programming

In the final paragraph, the speaker reflects on the current state and potential future of functional programming. They acknowledge that while pure functional programming may be impractical due to the inherent statefulness of computers, the principles of functional programming have been integrated into popular programming languages. The speaker advocates for a balanced approach, adopting functional principles where they make sense without the constraints of a purely functional style. They also speculate on the possibility of functional programming becoming more prevalent in the future, especially in the context of parallel computing and distributed systems.

Mindmap

Keywords

💡Functional Programming

Functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids changing state and mutable data. In the video, it is presented as a way to write programs without side effects, focusing on the purity of functions that always produce the same output given the same input. The speaker discusses the challenges and benefits of adopting functional programming principles in modern languages like JavaScript.

💡Currying

Currying is the process of transforming a function that takes multiple arguments into a sequence of functions that each take a single argument. In the context of the video, currying is used to create a new function from an existing one by binding a value to it, allowing for more flexible and reusable code. The speaker illustrates this with an example of a function that checks if a receipt belongs to a user, where the userId is bound to the function to simplify the filtering process.

💡State Management

State management refers to the way applications handle the state (data that can change over time) in a program. The video emphasizes the functional programming approach of avoiding state by not mutating variables or objects, which leads to more predictable and easier-to-test code. The speaker contrasts this with traditional programming paradigms that often rely on mutable state to track progress or changes in a program.

💡Recursion

Recursion is a technique in programming where a function calls itself to solve a problem by breaking it down into smaller instances of the same problem. In the video, recursion is presented as a way to replace loops in functional programming, as it naturally fits the paradigm's avoidance of state mutation. The speaker demonstrates how to convert a for loop into a recursive function to process a list of receipts.

💡Lambda Functions

Lambda functions are small anonymous functions that can be passed around and used as arguments or return values. They are a key feature in functional programming languages and are used to create functions on the fly. In the video, lambda functions are used to simplify the code by allowing the speaker to pass a condition directly into a higher-order function like filter, making the code more concise and readable.

💡Higher-Order Functions

Higher-order functions are functions that take other functions as arguments, return a function, or both. They are a fundamental concept in functional programming and enable powerful abstractions. The video mentions higher-order functions like map, filter, and take, which are used to transform, select, and limit data respectively, showcasing how they can be chained together to create complex data pipelines.

💡Data Pipeline

A data pipeline is a series of operations or transformations applied to data in a specific order. In the video, the speaker creates a data pipeline using functional programming techniques to process a list of receipts, filter them based on conditions, map them to different representations, and then take a subset of the results. This approach allows for a clear and declarative style of programming where the intent is expressed directly in the code.

💡Side Effects

Side effects are actions or changes that occur in a program other than the return value of a function. They often involve modifying global state or external resources. The video discusses the importance of avoiding side effects in functional programming to ensure that functions are pure and their behavior is predictable, which is crucial for maintaining the integrity and reliability of the code.

💡Immutable Data

Immutable data is data that cannot be changed after it has been created. In functional programming, the use of immutable data is a core principle that helps prevent side effects and makes it easier to reason about the program's behavior. The video touches on the idea that by not allowing data to change, functional programming promotes a more straightforward and error-resistant approach to software development.

💡Pure Functions

Pure functions are functions that, given the same input, will always produce the same output and have no side effects. They are a fundamental concept in functional programming and are used to create reliable and testable code. The video highlights the beauty of pure functions and how they contribute to the elegance and simplicity of functional programming, even though they can be challenging to implement in practice.

Highlights

Functional programming is often misunderstood due to its complex terminology and mathematical roots.

The core concept of functional programming is the purity of functions, which have no side effects and always produce the same output for the same input.

Functional programming avoids state and mutable variables, leading to a different approach to iteration and loops.

Recursion is used in functional programming as a form of iteration, replacing traditional loops.

Functional programming uses functions to manage state and control flow, such as through currying and lambda functions.

Currying allows functions to be created on-the-fly with bound data, similar to object-oriented programming's instance creation.

Functional programming can simplify code by creating data pipelines that filter, map, and transform data.

JavaScript has built-in methods that support functional programming, such as map, filter, and sort.

Functional programming can lead to more concise and readable code, as demonstrated by the transformation of procedural code into a functional pipeline.

The speaker proposes a startup idea, Black Sky Financial, which uses functional programming to detect and prevent credit card fraud in restaurant transactions.

Pure functional programming is often impractical due to the stateful nature of computers, but its principles can be applied selectively for benefit.

Functional programming patterns are becoming more common in modern programming languages, allowing for more efficient data handling and parallel processing.

The speaker encourages functional programmers to focus on the practical benefits of functional programming rather than its complexity.

The transcript ends with a call to action for functional programmers to share their knowledge and help others understand the practical applications of functional programming.

Transcripts

00:00

Dear functional bros, I see you.

00:03

I hear you.

00:05

And I love you.

00:07

Functional programing is awesome, but

00:09

functional programmers are bad marketers

00:12

talking about currying, your monads, binding, functors.

00:16

So many words.

00:17

I'm not sure anyone truly understands what all these things mean

00:21

because they really lie on some spectrum between the math of category

00:25

theory, lambda calculus, and their specific mapping

00:28

to different language implementations

00:32

But still, I do understand the beauty of it.

00:35

The concept of a function is so pure.

00:38

You have this elegant thing that takes an input

00:41

and gives you an output,

00:45

and no matter what, the same input

00:47

always gives you the same output.

00:52

The key thing that ensures that it gives you

00:54

the same answer always for infinity is that there's no side effects.

00:58

There's no state.

01:05

No thing inside of the function

01:07

that isn't directly derived by the input.

01:14

Once you introduce state, the outcome of the function

01:16

can vary based upon that state.

01:29

Honestly, most programing

01:30

paradigms are really just different takes on how you manage state.

01:34

It's all about state.

01:36

So let's talk about what functional programing is, why it kind of sucks,

01:40

but why adding a little bit to your code is awesome.

01:51

Functional programing

01:52

takes one extreme side of the state opinion.

01:55

It's about writing programs based upon one core concept.

01:59

There shall be no state.

02:01

You have inputs which are transformed into outputs

02:05

in order to get stuff done

02:06

you compose and connect functions to other functions,

02:10

hooking up their inputs and outputs together into one big long chain

02:13

that achieves the goal of the program.

02:17

But you don't have objects or structures

02:18

in memory that you mutate to track what's going on.

02:22

In this absolute pure world where you want to write functions with no state.

02:27

This also means that you're not allowed to mutate variables.

02:30

So this means if you were to set a value, you cannot change it again.

02:34

This means conventional iteration loops like for and while are impossible.

02:39

if you think about a for loop or a loop, it requires you to mutate some state,

02:43

at least some variable that's tracking how many times you've iterated

02:48

So how do you do a loop in a pure functional way?

02:52

The answer with functional programing is usually

02:55

well, more functions. When all you have is a hammer...

02:58

This is the part that we want to repeat over and over again.

03:01

So we'll just pull that part out to a function.

03:04

So now we need to replicate the three parts of the for loop.

03:08

The key thing that the for loop does is increment the index variable

03:11

so that the body gets a rerun with each index.

03:14

So we need an equivalent of incrementing index

03:17

and rerunning our body inside of processReceipt.

03:21

Since we can't mutate index, you can imagine us creating

03:24

a new variable, next index, which contains the next index

03:27

we want to process.

03:30

But now we want to repeat this section again.

03:32

So we'll need to call process receipt again.

03:35

So now if you were to call processReceipt, let's say

03:38

with an index of 2

03:41

It would print the merchant from index 2

03:43

then recall process receipt with index 3

03:47

then 4, etc.

03:50

but as it is now, it'll keep calling the processReceipt() forever until it goes

03:54

beyond the size of the receipt array causing an error to be thrown.

03:59

And this is where the second part of the for loop comes into play.

04:02

The condition.

04:04

We only want to execute the body if the condition is met.

04:07

Otherwise we do nothing and move on.

04:10

So we'll move that condition down into our function

04:12

where we only do anything if our index is still in range.

04:16

You can see when we run the program

04:18

it works like before.

04:19

It increases the index beyond the size of the array

04:22

and we still call our function.

04:25

But in this

04:25

case, it fails our condition and we do nothing.

04:29

This breaks the recursive loop and all our functions return

04:32

Recursion is just a fancier form of iteration.

04:37

And finally, we have our last part of the for loop.

04:40

which is where we set our starting point.

04:42

This just represents our first call into our recursive loop.

04:45

So now we've completely converted our loop to be done in the more functional way,

04:50

We can also remove any unneeded variables to make our code more concise.

04:53

If we wanted.

04:55

Okay, this is pretty simple and just logs each item in the loop.

04:59

But what if we wanted to do something useful, like

05:01

finding all the receipts that belong to a particular user and return them

05:05

so they can be displayed elsewhere?

05:07

well, we can take the userId as a third parameter

05:10

and then check if the user matches. This

05:13

now only prints the receipt of the merchant if the userId.

05:16

matches.

05:18

But instead we want this function to return the list

05:20

of matching receipts so that it can be displayed on the web app.

05:23

We need to somehow return the results of the matching. At each recursive call

05:28

we want to make an array with the current receipt at the front

05:32

and the results from the deeper calls attached to the end.

05:35

This way we can get back everything in order.

05:38

But we only want to append the current item if it has the right user ID.

05:43

Otherwise we just want to pass through the previous result

05:48

So, in order to do this

05:49

we’ll actually get the results of the deeper calls first.

05:52

And then if the userId

05:54

matches will return the current results appended to the later results.

05:58

Otherwise just forward on the later results as is.

06:02

And lastly, if we've processed the entire list,

06:04

we'll just return empty results since there's no more results to be had.

06:08

So now this function just returns all the receipts for a given userId

06:13

and we'll give it a better name.

06:16

Thing is that you can imagine this pattern happening over and over again

06:19

whenever you wanted to find stuff in an array.

06:22

The only difference between these functions is the condition in the

06:25

if statement.

06:26

We could replace all three functions

06:28

with just one if we instead passed in a function that returned.

06:32

Whether or not an item should be included.

06:35

Let's pull out the condition and move it to its own function.

06:38

And instead of taking the user idea as a parameter, we'll pass in that function

06:42

instead. We can call it condition.

06:45

Or if you want to be a classy fellow, you can call it predicate.

06:49

Then we just call that function where the condition used to be.

06:52

And that function tells us whether or not to include the item.

06:56

Then we can pass our condition.

06:57

The userIdEquals function into our filter.

07:01

And of course, we can now

07:02

rename our function to be a generic filter.

07:08

Now we can run our beautiful program with our filter and userIdEquals function.

07:12

and wait. We have a problem.

07:15

Our userIdEquals function takes two parameters

07:18

the receipt and the user idea to check against,

07:20

but our filter function only checks against the receipt itself.

07:24

We don't know the userId to check against.

07:27

We could try passing in another value that we could relay into the function.

07:32

But what if we need more than one?

07:33

Like in the case we needed to check if the total was between

07:36

a range, It gets a bit awkward.

07:39

So instead we're going to get a bit fancy here.

07:42

Instead of having our userIdEquals function, take both a receipt

07:45

and a userId,

07:47

we're going to have it take only the userId that we want to compare against

07:51

and it will construct and return a new function that takes a receipt

07:55

and returns whether it's from the userId.

07:58

We then pass in that new function that's been created into our filter.

08:03

This is a little weird, but what's happening is that the userId

08:07

is like a secret extra parameter which is bound to the function.

08:11

And this

08:12

function remembers that value and can use it.

08:15

The name for this pattern is called currying.

08:18

Instead of handling the entire operation at once,

08:21

it returns a function that handles the next part of the operation

08:25

The later part has the previous state bound to it.

08:29

That new on the fly created function is what gets called

08:32

when filter needs to check a condition.

08:43

This is what's a bit funny to me because functional programing

08:47

is supposed to be so different than object oriented programing.

08:51

But by finding data like this, we're creating an instance of a function

08:55

with some bound data to work with.

08:58

Instead of creating an instance of a data object

09:00

with its bound functions.

09:04

Currying like this is a bit of an older way of doing this.

09:08

You can automate

09:09

this in JavaScript in many other languages by using Bind.

09:13

I won't go into bind fully here because really the way

09:16

we want to do this today is to use Lambda functions.

09:19

This is where we'll move our equals check right

09:22

into an inline function.

09:25

Now this is finally where things start to get kind of nice.

09:28

I'm filtering by user now, or I can filter by merchant just like this.

09:33

or do a more complex check on the total here.

09:36

We might want to get just a filtered merchant names

09:38

instead of the entire object.

09:41

If we devise a new function based upon our loop

09:44

that doesn't filter based upon a condition,

09:47

but instead takes a function that gives you the desired results for each element.

09:51

we insert that new transformed element into the array

09:54

instead. We'll call this function map

09:57

because it maps each element to a different thing.

10:02

Then we can change these together.

10:04

So first we get our list of receipts.

10:07

Find the ones with a total between 14 and 20, and then just say: for each

10:11

give us the merchant name.

10:16

So now we get an array of the merchant strings

10:18

instead of the full receipt objects.

10:20

At the end.

10:22

And if we only wanted to

10:23

take the first five items, we could write a function called Take

10:27

Take would give us up to the count elements from the array.

10:31

We can chain that on as well.

10:33

So now you can see that we basically created a data pipeline here

10:37

Where we have an input state, we filter it down to what we want, map

10:41

the types of the values to what we want, and then take the first five to display.

10:47

Our code clearly declares what we want to happen,

10:50

and all the complexity

10:51

of how this is done is behind the scenes in our fundamental functions.

10:55

So we've just derived these functional style fundamentals ourself,

11:00

but these are also built directly into JavaScript.

11:03

So let's take a look at how to use those to create data pipelines.

11:08

But first, what's our goal with these receipts?

11:12

We have this amazing new startup idea

11:14

that solves a uniquely American problem in an American way.

11:18

In the U.S.

11:19

when you're in a restaurant,

11:20

you need to fill a tip manually by writing the tip and total.

11:25

This is effectively a mandatory fee

11:27

on your meal enforced by social shaming.

11:30

Your card is initially charged for the total without the tip.

11:33

But several days later, the updated total with your hand scribbled tip will show

11:37

up on your credit card.

11:39

The problem here is that no one is really going to check

11:41

whether their tip was accurately reported when their transaction was settled.

11:46

So in theory, a company or a disgruntled service staff

11:49

could simply enter a bigger number

11:50

taking more of your money.

11:52

Are you worried about losing your hard earned money to restaurant

11:55

credit card fraud?

11:56

Black Sky Financial finds these small family owned mom

11:59

and pop restaurants and sues them for everything they have.

12:04

The proceeds from the destruction of people's dreams

12:06

are then equitably distributed to you:

12:08

The user of the app based upon how many receipts you've submitted.

12:13

Sign up today and start submitting receipts

12:15

and know that you're helping prevent credit card fraud in your community!

12:18

One lawsuit at a time.

12:21

So, yeah, to pull this off, we basically need to grab each receipt,

12:25

look up the transaction in the user's connected credit card accounts, filter out

12:28

the transactions that haven't yet settled or whose totals match correctly.

12:33

Sorting by the most egregious discrepancy and then take the top ten.

12:38

Then we display them in a dashboard so our army of lawyers can get to work

12:41

fighting the good fight.

12:44

Here's that code written in a procedural way.

12:47

Let's change this to the functional approach.

12:50

In modern JavaScript

12:50

all the methods that we need are already built in

12:53

and are also methods directly on arrays.

12:57

For each receipt.

12:58

we eventually want this result object

13:00

that contains all of the relevant information:

13:02

the receipt, the final transaction, and the discrepancy.

13:06

So we can just map our receipts to that.

13:08

We can use the built in map method on our array

13:11

to transform the array into our list of objects.

13:15

The map method takes that lambda function for transforming our receipts

13:18

into those result objects.

13:23

This condition is skipping over the transactions that aren't yet settled

13:27

or don't have a difference

13:28

between the receipt total and the final total on the transaction.

13:31

So we can just change this to a filter.

13:34

We'll need to inverse the condition since it now describes

13:37

what to keep instead of what to ignore.

13:41

This code basically just ensures that the list is sorted from

13:44

biggest to smallest, So we can replace this with a sort on our filter list.

13:49

The sort takes a function that tells the sort function

13:51

how two elements should be ordered.

13:53

It gives you two items and asks for a negative number

13:56

if A is less than B and a positive of A is greater than B.

14:00

You typically get this by subtracting B from A, but since we want

14:04

things ordered big first we’ll flip this and subtract A from B,

14:09

and then we only want count number of elements

14:11

which we can get with the slice method, which we were already doing here.

14:16

So we'll just add that into our pipeline And voila.

14:20

After we make the formatting a bit more pretty,

14:23

all of that is written only in 12 lines.

14:26

Functional programing

14:26

lets you rewrite things into a beautiful pipeline for your data.

14:30

And honestly, most of the programing jobs are really just taking data from Source

14:34

A, doing some transformation, filtering, and sorting and then putting it in place

14:39

B. A lot of the time we're just sophisticated plumbers.

14:43

if you'd like to try out some functional programing like this,

14:46

I put some experiments on my website accessible through my Patreon.

14:50

I give you some procedural code and ask you to change it

14:52

so it doesn't use any for loops or a while loops.

14:55

If you’re curious, check them out at CodeAesthetic.io

15:00

Dear Functional Bros,

15:02

Sometimes I feel like you focus on the complexity

15:04

and mathematical elegance of functional programing.

15:08

Instead of explaining

15:08

why it's awesome and help others see how useful parts of it can be.

15:13

Maybe we need a special F bro signal

15:15

to let others know that you're also a secret F Bro.

15:19

Then you could talk about F Bro things like monads.

15:23

But if you don't get the signal, we can play it

15:24

chill and talk about how nice it is to delete for loops.

15:30

Pure functional programing

15:31

where you cannot mutate any state or have any side effects

15:35

is kind of awful.

15:37

The issue is its fake.

15:38

Computers fundamentally have state.

15:40

I mean, literally the whole von

15:41

Neumann architecture is where you have one giant state in memory

15:46

and then little instructions which mutate that state to get stuff done.

15:49

Input is non deterministic and any output is forcing some side effect.

15:55

Pure functional programing is still mostly academic,

15:58

But what has been happening is the best parts of functional programing

16:01

have been extracted and injected into our most popular languages.

16:05

Like always balance is key.

16:07

And adopting some of the principles like reducing state and formulating data

16:11

pipelines in your programs where it makes sense can bring huge benefit.

16:14

But without all the crazy restrictiveness.

16:17

And I'd expect more of these patterns to become more common.

16:20

Massively parallel systems don't rely on using one big state of memory.

16:24

The more cores you throw at something, the more tracking your state of memory

16:28

and elsewhere becomes bottleneck.

16:31

So who knows?

16:32

Maybe pure functional programing will have a new renaissance.

Rate This

5.0 / 5 (0 votes)

Related Tags
Functional ProgrammingPure FunctionsState ManagementCurryingLambda CalculusData PipelinesSide EffectsProgramming ParadigmsSoftware DevelopmentTechnical EducationWeb Development