Functional programming

Advent of Functional PHP: Day 2

Submitted by Larry on 2 December 2021 - 11:46am

In today's challenge, we're asked to interpret a series of basic command lines from a file and update the position of our submarine accordingly. It's basically a graph walk of sorts, with instructions of up, down, and forward. (Apparently you cannot go backward, as in life.)

As with yesterday's challenge, we could do it imperatively with a foreach() loop and a couple of state variables floating around, but that conflates a whole bunch of different behaviors into one blob of code. We don't want to do that, so let's step back and consider the problem more clearly.

Advent of Functional PHP: Day 1

Submitted by Larry on 1 December 2021 - 11:24am

today's challenge asks us to interpret a list of numbers. In the first part, our goal is to determine how many elements in the list are larger than their immediate predecessor.

The imperative way would be to toss it in a `foreach()` loop and track some state along the way. But we want to be functional and avoid "track some state," because the whole point of functional programming is to avoid tracking state, as tracking state is error prone.

When looking at a foreach-style operation that has some state, my first inclination is to look at a reduce operation. A reduce operation walks over a list and performs the same operation (function) on each item, using the output of the previous iteration as an input. That is, each step takes the output of the previous operation and the next element, and produces an output. It's quite elegant.

Advent of Code 2021: Functional PHP

Submitted by Larry on 29 November 2021 - 6:45pm

I am planning to participate in Advent of Code this year. For those not familiar with it, it's a daily coding challenge that runs through December, until Christmas. Mostly it's just for fun, but some people take it as an opportunity to either push themselves (by solving the puzzles in a language they're unfamiliar with) or to show off some feature of a language they like, which they then blog about.

In my case, I'll be solving puzzles in PHP, of course, but specifically using functional techniques. My goal is to demonstrate how functional programming in PHP is not just viable but creates really nice solutions. At least, I hope it works out that way; I haven't seen any of the challenges yet. :-)

The case for partials and pipes in PHP

Submitted by Larry on 23 June 2021 - 3:07pm

The Partial Function Application RFC is currently in voting, and right now it's a close vote to the negative. I wanted to take this opportunity to try and make the broader case for partial application and for its related RFC, the pipe operator, in a way that is more appropriate for a blog post than the RFC body (which is, by design, more concerned with the finer details of "what").

The main pushback on the RFC so far is that the benefits don't outweigh the cost of yet-more-syntax in the language. Which is a fair position to hold, albeit one I hope to convince you is incorrect. That is, I believe the benefits vastly outweigh the syntax and implementation cost.

Continue reading this post on PeakD.

One year of functional PHP; now in Russian!

A year ago, I published my first solo book, Thinking Functionally in PHP. The reception has been extremely positive; almost everyone that's read it (that has bothered to talk to me about it) has found it clear, helpful, and enlightening. Mission accomplished!

To celebrate the one year anniversary of the book's publication, I am happy to make two announcements.

First, Thinking Functionally in PHP is now available in Russian! The translation is by Alexey Pyltsyn, who is responsible for the Russian translation of the PHP documentation as well as numerous other tech book translations.

Larry 11 May 2021 - 8:14pm

Byte-sized functional programming: Composition over inheritance for functions, too

Submitted by Larry on 15 August 2020 - 10:07am

A popular refrain in object-oriented code is to favor object composition over inheritance. It offers more flexibility, less overhead, and ends up being easier to reason about. The same concept applies to functions, too!

A common pattern is to have a function that does some work and then calls another function, which does some work and calls another function, and so on. The problem is that the first function then cannot be used or tested without the entire chain of other functions it calls. This is the function equivalent of "inheritance."

Instead, we can compose functions, that is, pipe them together. Instead, take the output of the first function and pass it to the second, then take the second's output and pass it to the third, etc. That way, each of the functions can be reused, tested, and understood in isolation, then we can stick them together like LEGO blocks to build whatever series of steps we want.

That is, instead of this:

<?php
function A($in)
{
  
// ...
  
return B($out);
}

function

B($in)
{
  
// ...
  
return C($out);
}

function

C($in)
{
  
// ...
  
return $out;
}
?>

Structure it like this:

<?php
function A($in)
{
   
// ...
   
return $out;
}

function

B($in)
{
   
// ...
   
return $out;
}

function

C($in)
{
   
// ...
   
return $out;
}

function

doit($in) {
   
$out = A($in);
   
$out = B($out);
   
$out = C($out);
    return
$out;
}
?>

Now `A()`, `B()`, and `C()` are all easier to read, understand, and test, and we can more easily add a step B2 or D if we want. So powerful is this concept that many languages have a native operator for piping functions together like that. PHP doesn't, yet, but it's straightforward enough to do in user space anyway.


Want to know more about functional programming and PHP? Read the whole book on the topic: Thinking Functionally in PHP.


Thinking Functionally in PHP

Byte-sized functional programming: Filter first

Submitted by Larry on 3 August 2020 - 1:47pm

Often when working with a list, we only want to work with a subset of a list that meets some criteria. All non-zero values, for example, or all users that have a given role. The procedural way to do that is to stick an if statement inside a foreach loop:

<?php
foreach ($list as $value) {
    If (!
meets_criteria($value)) {
        continue;
    }
   
// ...
}
?>

That mixes up the filtering with the iteration, though. It also doesn't work if we're using `array_map()`.

Instead, we can make stripping down the list a separate operation called "filter." PHP offers the array_filter() function for that purpose.

<?php
$criteria
= fn(User $user): bool => $user->hasRole('moderator');

$filtered = array_filter($users, $criteria);
?>

Now we can work with the `$filtered` list, which has only the values we want. That could be a simple foreach<code> loop, or, better, it's now ideally suited for use with <code>array_map().


Want to know more about functional programming and PHP? Read the whole book on the topic: Thinking Functionally in PHP.


Thinking Functionally in PHP

Byte-sized functional programming: Mapping out your data

Submitted by Larry on 27 July 2020 - 3:42pm

Procedural code tends to think in terms of writing out steps, and so the usual way to work with a list is to iterate it using a `for` or `foreach` loop.

Functional code tends to think in terms of the relationships and transformations between data, where those relationships and transformations are defined as functions. That means the natural way to work with a list is to define a function that is the relationship between one list and another. The most common way of doing that is with a "map," which in PHP usually means the `array_map()` function.

With `array_map()`, you give it an array and a function. You get back the result of applying that function to every element in the array, individually. Like so:

<?php
$arr
= [1, 2, 3, 4, 5];
$fun = fn($x) => $x * 2;
$result = array_map($fn, $arr);
?>

The advantages of that over a `foreach` loop are:

* The function is a separate operation that can be as complex as you want.
* If it's more than a line or two, make it its own function or method somewhere and test it in isolation.
* If it's trivial, you can simply inline it.
* It's clear, visually, that every element's transformation is independent of every other's, because that's how `array_map()` works. A `foreach` loop may maintain state from one iteration to the next, but `array_map()` does not.


Want to know more about functional programming and PHP? Read the whole book on the topic: Thinking Functionally in PHP.


Thinking Functionally in PHP

Byte-sized functional programming: Immutable variables are easier to understand

Submitted by Larry on 21 July 2020 - 7:30am

An immutable variable is one whose value doesn't change after it has been first set. PHP doesn't natively support that, but we can write our classes in such a way to simulate it. For example, rather than this:

<?php
class Point
{
   private
int $x;
   private
int $y;
 
   public function
__construct(int $x, int $y)
   {
      
$this->x = $x;
      
$this->y = $y;
   }
 
   public function
moveUp(int $by): void
  
{
      
$this->y += $by;
   }
}
?>

We can write this:

<?php
class Point
{
   private
int $x;
   private
int $y;
 
   public function
__construct(int $x, int $y)
   {
      
$this->x = $x;
      
$this->y = $y;
   }

   public function

moveUp(int $by): Point
  
{
      
$new = clone ($this);
      
$new->y += $by;
       return
$new;
   }
}
?>

In the second version, once a given `Point` object is created it will never change. We can safely pass it to another function or method and be guaranteed that its value won't change without us knowing. Instead, any attempt to change it results in a new object, with its own identity, representing the new point in space. (In practice there would be other methods here as well, but we're focusing on just the mutation part.)

Code that uses immutable variables is easier to think about, because we don't have to worry about "does passing this object to this function change it?" We know it doesn't. Once we know something about an object we can guarantee that fact doesn't change. That can make a lot of subtle bugs impossible, which means we don't have to spend time looking for or correcting them.


Want to know more about functional programming and PHP? Read the whole book on the topic: Thinking Functionally in PHP.


Thinking Functionally in PHP

Byte-sized functional programming: Pure functions make testing easy

Submitted by Larry on 14 July 2020 - 9:28am

When testing stateful code, you have to first set up all of the explicit and implicit state that a given piece of code depends on. If the object you're testing has many dependencies that could be complex, or references global variables, or calls many other routines with their own dependencies, you may be looking at a lot of complex setup that makes testing hard to do effectively.

Pure functions greatly reduce that problem.

A pure function is a function that:

  • has no inputs other than those explicitly specified;
  • has no effect on any value other than the value it returns.

That means there is, by definition, only one place to inject dependencies: the call itself. And there's only one effect to validate: the return value of the function. No need to call a function and check what the effect was on some other value or piece of code: by definition, the only effect is the return value.

If one of the parameters you pass in is itself complex, that may make the test complex. But if the parameter is complex, that can serve as an impetus to simplify it. Rather than passing in an object, for example, just pass in a single function. If that function in practice has more complexity behind it, fine, but it makes passing a mock function trivial. Just... make a new (anonymous) function for the one test.

When your code has fewer sneaky interactions, there's less effort involved in testing as well as fewer things to test.


Want to know more about functional programming and PHP? Read the whole book on the topic: Thinking Functionally in PHP.


Thinking Functionally in PHP