Welcome to an adventurous dive into the world of prime numbers, guided by none other than Expr, the sleek and flexible expressions language designed for Go. Whether you're safeguarding your business rules or simply indulging in the mathematical elegance of primes, Expr is your trusty sidekick. Today, we're embarking on a quest to uncover prime numbers in ways that are as engaging as they are enlightening. So, grab your math hat (yes, that's a thing now), and let's get started!

## Prime Check: Is My Number a Lone Wolf?

First off, let's tackle the burning question: "Is my number prime?" Imagine you're at a party, and 27 walks in. You whisper to Expr, "Hey, is 27 part of the prime clique?" Expr, always ready, responds with a slick one-liner:

`let N = 27; none(2..N-1, N % # == 0)`

Here, Expr takes the number 27 and checks if none of the numbers from 2 to 26 can divide it without leaving a remainder. It's like asking everyone at the party if they're best friends with 27 and finding out nobody is. Alas, 27 is not prime. But worry not, the party goes on.

## Prime Gathering: Who's Coming to the Prime Party?

Next up, we're throwing a prime party and need to send invites to all prime numbers from 2 to 1000. How do we find these exclusive guests? Expr to the rescue!

`2..1000 | filter(let N = #; none(2..N-1, N % # == 0))`

This nifty line asks Expr to hand out invites to numbers from 2 to 1000, but only if they pass the prime test. It's like having a bouncer at the door checking if the guests have any friends from 2 to one less than themselves. If not, welcome to the party!

## Eratosthenes' Sieve: The Prime Filter Party Trick

Now, for the grand spectacle: Eratosthenes' sieve. This ancient algorithm is like the coolest party trick for finding primes, and yes, Expr knows it too.

`let numbers = 2..1000; `

reduce(numbers, {

let n = #;

filter(#acc, # == n || # % n != 0)

}, numbers)

Here, we start with a list of numbers from 2 to 1000. Then, for each number, we filter out the non-primes by keeping only the number itself or those that it can't evenly divide. It's like having a magic sieve that only lets through the primes. Pure sorcery!

## The Memory Budget: Expr's Party Limit

But oh, what's this? There's a limit to how big our party can get. Expr comes with a concept called "memory budget," ensuring that our prime-finding escapades don't get too wild. For example:

`runtime error: memory budget exceeded (1:39)`

| 2..1_000_000 | filter(let N = #; none(2..N-1, N % # == 0))

| .......................................^

Trying to invite every prime between 2 and 1,000,000? Expr might just stop you there with a polite, "Sorry, that's beyond my memory budget." This ingenious feature prevents our prime quest from consuming more memory than allowed, ensuring that our computational party doesn't crash the server.

### How Does Expr Calculate This Budget?

Every operation in Expr has a cost, and as we weave through our expressions, these costs accumulate. Think of it as Expr having a certain amount of "computational currency" to spend on our tasks. If our expression's cost exceeds this budget, Expr kindly asks us to tone down the party. It's like trying to order a 5-course meal on a 2-course budget—something's got to give!

## Conclusion: Prime Time with Expr

And there you have it, folks! A whirlwind tour of finding prime numbers with the flexible and mighty Expr. From gate-crashing non-primes to hosting the most exclusive prime parties and managing our computational budget like a true event planner, Expr proves to be an invaluable companion in the realm of expressions.

Remember, the next time you're pondering the primeness of numbers or any other mathematical marvel, just call on Expr. It's your go-to for not just business rules but for unlocking the secrets of mathematics with elegance and a sprinkle of fun.

So, keep exploring, keep questioning, and most importantly, keep enjoying the mathematical festivities with Expr. Who knew prime numbers could be this much fun?