Can you solve FizzBuzz ... in a tweet?
Tags: ruby, lambda, functional
Published: 2021-08-23 20:17:48

FizzBuzz is a (in)famous programming puzzle that it is used mainly just to filter people who can code from people who can't.

The problem statement is as follows:
> Write a function that prints the 100 first integers, but for every multiple of 3 prints "Fizz" (instead or the number), for every multiple of 5 prints "Buzz", for a mutipe of both 3 and 5 prints "FizzBuzz",

One naive impementation would be something like:
```ruby
def fizz_buzz
  (1..100).each do |n|
    print 'Fizz' if n % 3 == 0
    print 'Buzz' if n % 5 == 0
    print n unless n % 3 == 0 || n % 5 == 0
    print "\n" 
  end
end
```
This works, but has several shortcomings with no easy workarounds. The most immediate one: you are checking modulo twice (or have cumbersome elses)

See this alternative:
```ruby
def fizz_buzz
  (1..100).each do |n|
    if n % 3 == 0
      puts "Fizz#{n % 5 == 0 ? 'Buzz' : ''}"
    else
      puts "#{n % 5 == 0 ? 'Buzz' : n}"
    end 
  end
end
```
Where you only repeat the 5 check, but the code is extra complex.

This is a bad test, not a good predictor of future software engineering performace. But that does not mean you cannot use it to learn stuff about ruby. For  example, you could choose to solve it with no if's, no methods, no classes and no method calls (other than operator-like)...

Let me take you to the end and then see how do we get there:
```ruby
-> n {
  t = ->(d, s, x) { n % d == 0 && -> _ { s + x[''] } || x }
  f = -> x { t[3, "Fizz", x] }
  b = -> x { t[5, "Buzz", x] }
  f[b[-> x { x }]][n]
}.yield_self { |fb|
  p (1..100).map { |n| fb[n] } * ','
}
```
What do we get here:
- "Fizz" appears only once
- "Buzz" appears only once
- 3 appears only once
- 5 appears only once
- modulo check is generalized and appears only once
- we use lambdas
- we use function composition
- we use higher order functions (functions receiving functions as parameter)

And now the parts:
## Test function
```ruby
t = ->(d, s, x) {
  n % d == 0 && -> _ { s + x[''] } || x
}
```
But for the analysis lets have better identifiers:
```ruby
test = lambda do |divisor, string, executable|
  # if the number is a multiple of divisor...
  number % divisor == 0 &&
    # return a lambda that prefixes string
    (lambda do |_| string + executable[''] end) ||
    # otherwise return the received function
    executable
end
```
I don't know how much ruby you know so I will try to explain it all:

`lambda` creates an anonymous method that can be stored in a variable or passed as argument
```ruby
a = lambda do |x|
  puts "#{x} #{x}"
end
a.call('hi')
```
prints `hi hi`

`->(x){ puts "#{x} #{x}"}` is just an alternate syntax to define lambdas, it is sometimes called the _stabby operator_ 
- https://ruby-doc.com/core/Kernel.html#method-i-lambda
- https://ruby-doc.com/core/Proc.html

Inside the test lambda we have this structure: `a && b || c`  `&&` is ruby _and_ operator (for expressions, there is also `and` for action, with different precedence)
 and `||` is the _or_.

This is used in substitution of `if` and `else`
`a && b` short-cirtuits in ruby so it only evaluates `b` if `a` is true (if `a` is false, the and already is).
On the other hand: `b || c` only evaluates `c` if `b` is falsey (if it's true, the expression already is)

So the translation of the test function is:
```ruby
test = lambda do |divisor, string, executable|
  if number % divisor == 0
    (lambda { |_| string + executable[''] })
  else
    executable
  end
end
```
This whole _return a function_ business sounds complicated but is key to be able to use test for both Fizz and Buzz

## Fizz function
Test function is pretty generic, but can be translated as: 
> if n is a mutiple of d, perfix s to what you receive, otherwise leave it be.

Being so generic, allows us to build two functions, `f` (for fizz) and `b` (buzz) by feeding different arguments to `test`, so 
```ruby
f = -> x { t[3, "Fizz", x] }
```
which can be translated to the verbose version:
```ruby
fizz = lambda do |executable|
  test.call(3, "Fizz", executable)
end
```
What `fizz`does is call `test` (`t`) with two literal parameters, `3` and `"Fizz"` and a dynamic one, `executable` (`x`).

With this example you can imagine that `buzz` (`b`) is constructed in very much the same way  replacing 3 with 5 and "Fizz" with "Buzz".

## Function composition
One of the things we did not like on the original version was the repeated checks. The only way to avoid them in this case is to nest them.

We are building a fizz function that receives a buzz function as an argument so that it can run that code sometimes.

There is a whole branch os programming/mathematics that deals with this kind of thing. It is called [Lambda Caculus](https://en.wikipedia.org/wiki/Lambda_calculus) and that is where the name of ruby's `lambda` function comes from.

## Multiple function composition
Now we have the last mysterious part:
```ruby
f[
  b[
    -> x { x }
  ]
][n]
```
f: returns a function that 
if n is divisible by 3
  returns a function that returns:
    "Fizz" + received code run on "" (empty string)
else
  returns a function that runs the received code
The code that f receives is `b[->x{x}]`

b: returns a function that 
if n is divisible by 5
  returns a function that returns:
    "Buzz" + received code run on "" (empty string)
else
  returns a function that runs the received code

But now the most important:
`b` receives this code `-> x { x }`
This is a function that returns its argument. Think of:
```ruby
def executable(x)
  return x
end
```
This is the part of the code that will return the integer ONLY when it is not a multiple of neither 3 nor 5 because, and this is the key, both `f` and `b` run this function on their `else` sides, and run something like `executable("")` (or `x['']` in the abbreviated version) instead when the modulo is 0.

I am almost sure that this might not be absolutely clear, so please, copy this code, paste it into your `irb`, play with it... and come with your questions.

I would love to improve this article with each question received in the comments, and encourage you to play with even the smallest piece of code you lay your hands on, to push the boundaries of your knowledge, or at east have some fun.