I think the best way to think of Active Patterns is that they're a way of separating input data for use in your pattern matching expressions.

As always, I also think that looking at an example first and working out what it does after, is the best way to understand a problem:

type Person = {Name: string; Age: int}

let adult = {Name = "Trevor"; Age = 32}
let child = {Name = "David"; Age = 17}

let (|GrownUp|Youth|) person = if person.Age < 18 then Youth else GrownUp

let findAgeGroup person =
match person with
| GrownUp -> printf "You're a grown-up\n"
| Youth -> printf "You're under 18\n"

findAgeGroup adult
findAgeGroup child

In the code snippet above you can see that first we define a simple record type called Person.

Next we create 2 Record Types, one who is an adult (18 or over) and one who is a child.

After that we have our Active Pattern definition. Essentially all this Active Pattern does, is takes in a Person and then if the Persons age is less that 18 it returns Youth and otherwise it returns GrownUp.

We then have a function called findAgeGroup which takes in a Person. That uses a match expression which uses our Active Pattern to decide which branch to evaluate.

One of the benefits of using Active Patterns like this are that you can hide away all your logic for pattern matching in the Active Pattern which keeps the findAgeGroup function cleaner.

Another benefit is that you can separate data types in multiple ways, but for this simple example we won't get into that.

This is a very brief look into Active Patterns and for a much deeper look I'd recommended reading the Microsoft documentation which can be found here: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/active-patterns

The reason that the image for this post is a banana is that the syntax that wraps the Active Pattern definition (|Wrapper|) are sometimes referred to as Banana Clips