00:00:25.199
Good morning, everyone! People are actually awake at this conference in the morning. It's weird.
00:00:32.880
My first tech conference was Golden Gate RubyConf 2010, where Jim Wyrick gave the keynote.
00:00:39.200
He covered a wide variety of topics, including physical chemistry, which is one of my favorite subjects. He mentioned a book called 'The Structure and Interpretation of Computer Programs', which he said had been recommended more than any other book to help professional programmers improve their craft.
00:00:51.520
As a result, he started a study group, and his keynote was about what his group had learned from the first two chapters of the book.
00:01:03.440
The book contains five chapters, and you can imagine the depth of content covered in just the first two chapters. About 50 to 60 minutes into his 90-minute keynote, he mentioned that everything he had covered so far did not use assignment.
00:01:16.320
In fact, this book doesn’t introduce assignment until chapter three, which is more than forty percent of the way through. That little nugget stuck with me, and that's kind of where this talk started.
00:01:28.479
A little bit about me: I'm Aja Hammerly, and I tweet under the handle @thagomizer_rb. I enjoy when people tweet at me during my talk since my phone is over there, and I will read all your comments later. Just make sure they're nice! I'm also on GitHub as @thagomizer and occasionally blog at thagomizer.com, mostly sharing my talk slides. These slides would be posted there, but I had a technical issue with rsync about an hour ago.
00:01:46.640
I work at a company called Substantial, a digital product studio in Seattle, Washington. If you're ever in Seattle, check out our website, substantial.com, where we host many events for nerds of varying kinds.
00:02:06.719
What qualifies me to give this talk? Quite frankly, not much. However, based on Jim's keynote, a few of us in the Seattle Ruby community started a study group through SICP, which took us about nine months to complete.
00:02:20.239
Ryan is going to talk about that later. I also conducted a study group on functional programming last fall using a different book. If you've seen me speak before, you know that I have a deep fascination with esoteric programming languages like Prolog.
00:02:39.120
Once I started exploring that, I began noticing functional programming concepts everywhere. So, what is functional programming?
00:02:50.800
According to Wikipedia, functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids mutable state and data. While that definition isn’t particularly insightful, one of my coworkers remarked that the concept of mutable state is suspicious and easy to mess up.
00:03:10.480
Jim provided a more practical definition in his talk: a functional language is about creating functions that do things, not just calling functions. For this talk, I will focus on a core aspect of functional programming: not using assignment.
00:03:29.680
There will not be a single equals sign in Ruby anywhere in this presentation. In Scheme, assignment is done using 'set!', but there won’t be any 'set!' operations in this talk either. I will also avoid modifying objects.
00:03:41.680
Setting expectations: I have 114 slides packed with code. I don't give fluffy talks, so be prepared for lots of parentheses! And no ponies... sorry, Mike.
00:03:55.760
Now, why should you care about functional programming? First of all, it's easier to test. There's significantly less setup and very little stubbing and mocking involved. Many times, on projects with functional aspects, we start from a known state.
00:04:13.360
This means your tests won't pollute your data across runs, and you avoid dependencies that might trip you up. Concurrency is also much easier in functional paradigms, where there’s no mutable state for threads to interfere with. It’s fantastic.
00:04:31.840
Functional programming advocates often talk about safe reuse—you can take a function from one project and move it wholesale into another, owing to the absence of mutable state. You also benefit from brevity, as functional programming languages like Scheme and Haskell are typically concise.
00:04:58.000
This brevity can be a double-edged sword, however, as some find it appealing while others might get frustrated by it. Ultimately, I think two of the biggest reasons to care about functional programming are that many of you are already using it and that Ruby makes it easy.
00:05:26.800
Raise your hand if you’ve ever passed a block to a method from Enumerable. That practice is heavily influenced by functional programming concepts. Since many of you are already doing it, you might as well learn the basics and utilize its strengths.
00:05:51.440
Moreover, Ruby natively supports many basic functional concepts, allowing easy integration of functional techniques without complex contortions. For instance, if you have a service in your Rails app that could benefit from functional ideas, you can implement them whilekeeping your rest of the Rails app in an object-oriented paradigm.
00:06:09.680
The functional language I know best, which also has real-world use, is Scheme. Let’s cover some basics of Scheme quickly.
00:06:27.919
The most important thing to know is that Scheme uses prefix notation, meaning that the function name appears before the arguments. In my slides, Ruby will be in red on the right, while Scheme will be in blue on the left.
00:06:46.240
For example, '5 + 3' in Ruby translates to '(+ 5 3)' in Scheme. Prefix notation allows for a variable number of arguments, so you can add or multiply multiple numbers in a single expression using the same method.
00:07:09.520
To define a function in Scheme, you use 'define' followed by the function name, arguments, and the method body. Instead of 'end', you just close with a parenthesis. Invocation is again straightforward—just the method name followed by the argument in parentheses.
00:07:29.520
For conditionals, functional programmers often use 'cond', which maps well to Ruby's 'case' statements. For example, an absolute value function can be built using 'cond' to evaluate cases based on the number's value.
00:07:53.039
In the first case, if the number is greater than zero, we simply return that number. If it’s zero, we return zero. Otherwise, we return the mathematical opposite using Scheme's unary minus.
00:08:12.400
Just as in Ruby, Scheme has an implicit return value for the last expression evaluated. However, this isn't how a true Schemer would write it, as brevity is preferred among them, leading to more condensed code.
00:08:30.640
Another conditional construct in Scheme is 'if'. A predicate function returns a boolean, and the structure leverages this by executing different branches based on the true or false evaluation of the condition.
00:08:54.000
The temperature example demonstrates this effectively: If it's above 65 degrees, it’s considered balmy, otherwise it is not.
00:09:13.280
Additionally, lists are fundamental in functional programming languages. In Scheme, you define a list using a single quote followed by parentheses and elements separated by spaces.
00:09:28.560
In Ruby, we use arrays like [1, 2, 3], whereas in Scheme and Lisp, the 'car' and 'cdr' functions are used to access the first element and the rest of the list, respectively.
00:09:43.440
Finally, the concept of checking whether lists are empty and utilizing 'null?' in Scheme corresponds to 'empty?' in Ruby. Scheme denotes true as '#t' and false as '#f'.
00:10:02.960
Now, let’s dive into recursion, one of my favorite topics, starting with a factorial definition in both Scheme and Ruby. If the number we're calculating is one, we return one; otherwise, we multiply the number by the factorial of the number minus one.
00:10:22.960
We've been calculating the factorial of five recursively: 5 times the factorial of 4, and so on, down to factorial of 1.
00:10:41.680
Recursion is fascinating and powerful in functional programming languages. Allow me to show you a Scheme implementation of the Fibonacci sequence next.
00:11:01.600
In this implementation, if n is zero, we return zero; if n is one, we return one. Otherwise, the nth Fibonacci is the sum of the Fibonacci numbers for (n-1) and (n-2). This closely mirrors Ruby's definition as well.
00:11:20.240
While these examples are fantastic, tail call optimization further enhances the performance of recursive functions. For example, let’s look at exponentiation.
00:11:38.000
In the basic exponentiation function, we compute b to the power of n by repeatedly multiplying b times b raised to the n-1.
00:11:56.280
However, the depth of the call stack can become excessive with this version if we raise very large powers. Regardless, we can optimize this using tail call optimization.
00:12:14.400
The alternative involves defining an accumulator that takes in our current product. We reduce the counter and increase the product with each recursive call until we reach zero.
00:12:36.720
Thus, we still make the same number of calls, but because all calculations are done immediately, we reduce the stack workload significantly.
00:12:56.240
Now, I want to present a classic functional programming example: making change. The task is to figure out how many ways you can make change for a dollar using half dollars, quarters, dimes, and nickels.
00:13:20.000
Initially, I thought the task was too challenging, so I opted to simplify it and determine how many ways I could make some amounts using various coin denominations.
00:13:43.760
As before, I defined a function called 'count_change', in which the amount is represented in cents. I'm assuming an infinite supply of coins for simplicity.
00:14:02.560
First, let's handle the case where there are no coins; in that instance, making any amount is impossible, so the function returns zero ways.
00:14:21.440
Next, we look at a base case: if the amount equals the first denomination, we return one way; if we have a penny and we want to make change for one cent, we can use exactly one penny.
00:14:41.760
In cases where the amount does not correspond to one denomination, we must invoke recursion to explore remaining values. Starting with a penny, we calculate how many ways we can make the amount with the remaining coins.
00:15:03.520
If we try using nickels and pennies, we discover that we can make five cents using either one nickel or five pennies, leading to some recursive exploration.
00:15:26.880
My testing revealed that, while my implementation was working, I needed to ensure each denomination's availability during recursion to accurately gauge change possibilities.
00:15:49.200
By reconstructing the recursive calls based on the denominations array, I could evaluate both scenarios: making the amount using a nominal value or not.
00:16:07.600
We can apply the 'no penny' case and sum it with the 'penny' option to derive the final outcomes. After refining my code through testing iterations, I could confirm these results.
00:16:29.920
Finally, I went back to the primary challenge: making one dollar worth of change. After implementing this with effective recursion, the answer was ideally calculated to be 292 possible combinations.
00:16:47.760
This solution, appearing much cleaner in Scheme, indicates how powerful concise functional expressions can be in handling complex problems.
00:17:06.640
To summarize, we explored different functional techniques and their advantages such as list operations, predicate behavior, and exhaustive enumeration within Ruby and Scheme, emphasizing their versatility across languages.
00:17:27.120
In particular, Ruby supports functional programming intuitively, enabling us to apply these concepts seamlessly in our code.
00:17:46.000
To deepen your understanding, I highly suggest further exploration into functional programming concepts, as they can greatly enhance your programming repertoire, particularly in Ruby.
00:18:05.200
I encourage those interested in functional programming to check out resources like 'The Little Schemer', which is concise and engaging, or 'Structure and Interpretation of Computer Programs', also known as the wizard book.
00:18:25.200
Both books dive deep into various concepts, promoting a better understanding of functional language theory and application.
00:18:43.200
You can also find numerous lectures online focusing on the intersection of functional programming and Ruby, which could greatly benefit your journey into this paradigm.
00:19:03.680
Events like Ruby Midwest and Goruco often feature talks on functional programming, and watching speakers like Pat Shaughnessy and Jessica Care can offer you diverse insights into the topic.
00:19:25.760
In particular, I highly recommend Jessica's presentation on functional principles in object-oriented development, which provides excellent perspectives.
00:19:47.840
Lastly, Jim Wyrick's 'Adventures in Functional Programming' is a fantastic resource, delivering dense information that made the subject enlightening while still challenging.
00:20:11.840
The need to cite images in presentations is important. I had one this time: the boring board pony. Thank you very much for your attention.
00:20:32.240
I have a moment for just one quick question.
00:20:40.840
Someone asked about my opinion on the Closure programming language. Though I haven't personally used it, those I know who have really enjoyed it, so it seems promising.
00:21:00.159
Okay, thank you all!