Library / SDK
dbrattli/Expression avatar
dbrattli/Expression

Expression: pragmatic functional programming for Python with F# ideas and Option types

Functional programming for Python

784 stars38 forksPythonMIT

At a glance

What is it?
Expression is a MIT licensed library that brings functional programming to Python 3.10 and later using F# as the reference rather than Haskell, with Option and Result types, pipeline and pipe friendly methods, and a seq module for working with collections. It deliberately avoids currying, operator overloading and recursion, and its stated goal is code that still looks like Python.
Who is it for?
Expression fits a Python team that wants optional values and expected-failure results handled explicitly, or an F# developer who needs to work in Python without writing it as a translation, and who is willing to accept a type-annotated, Pylance-clean codebase. It does not fit a codebase that will not adopt annotations, or a team that wants a dependency-free way to model absence.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What pragmatic means in this library

Expression is described as a solid, type-safe, pragmatic and high performance library for frictionless and practical functional programming in Python 3.10 and later, and the word pragmatic is doing deliberate work.

The README defines it directly. By pragmatic, the goal is to use simple abstractions to enable practical and productive functional programming in Python, instead of being a Monad tutorial, with a link to the author's earlier OSlash project as the thing being rejected.

The framing is that Python already supports functional constructs such as functions, higher-order functions, lambdas, and in many ways favours composition over inheritance, so a library that adds Haskell's abstractions on top is adding a second language's idioms to a language that already has its own. Expression's response is to take F# as the reference instead.

That reference point explains the whole design. The stated purposes are to enable functional programming in a Pythonic way, meaning not over-abstracting things, so Expression does not require purely functional programming as a language like Haskell would. Everything you learn with Expression can also be used with F#, so the aim is to learn F# by starting in a programming language you already know. And it makes it easier for F# developers to use Python when needed, and to reuse concepts and abstractions they already know.

The line that captures the library's voice is short: expressions evaluate to a value, statements do something.

The goals, including what the library refuses to do

The goals list is unusually specific, and the negative items matter as much as the positive ones.

The library is an industrial strength library for functional programming in Python, and the resulting code should look and feel like Python, following PEP 8, because the aim is a better Python and not an obscure DSL or an academic Monad tutorial.

There is pipelining and pipe friendly methods, compose all the things, and dot-chaining on objects as an alternative syntax to pipes.

Then the list of things it wants to avoid, in the service of lowering cognitive load. It avoids currying, which is not supported in Python by default and is not a well known concept to Python programmers. It avoids overloading operators such as the pipe or the shift, because that usually confuses more than it helps. And it avoids recursion, which is not normally used in Python and any use of it should be hidden within the SDK.

Those three exclusions are the design in miniature.

The remaining goals are about typing. Type hints for all functions and methods, support for PEP 634 and structural pattern matching, code that must pass strict static type checking with Pylance, and Pydantic friendly data types, with Expression types usable as part of your Pydantic data model.

What the F# reference buys you

The README lays out the case for F# as the model, and it is worth reading because it explains the shape of the API rather than the implementation.

F# is described as a functional language for .NET that is succinct, readable and type-safe, and in many ways Pythonic, since Python is in many ways similar to F# but F# can do a lot of things better than Python.

The three advantages listed are the ones that shape a library like this. Strongly typed, so if it compiles it usually works, which makes refactoring much safer, and where the type system can be trusted. Type inference, so the compiler deduces types during compilation. And an expression based language.

The type system point is the one that matters for a Python project specifically, because it is about the tooling. The README contrasts it with mypy and Pylance, where you often wonder who is right and who is wrong, and Expression's answer is that the F# model has no such ambiguity.

The consequences for the API are visible in the type names themselves. Option is for a value that may be absent, Result is for a caller who needs an expected failure reason, and the library's own description mentions railway oriented programming for better and predictable error handling, pipelining for workflows and computational expressions.

That is a coherent set of ideas borrowed from one language, and the point of taking them from F# rather than Haskell is that F# and Python share enough syntax that the translation is small.

Getting started with the pipeline and seq module

Installation is a pip install, and the library only works for Python 3.10 and later:

console
> pip install expression

There is a Pydantic v2 extra:

console
> pip install expression[pydantic]

The documentation suggests starting with a practical workflow rather than with the type system, and gives three common needs: transform an iterable in readable steps with pipe and Seq, use Option when a value may be absent, and use Result when a caller needs an expected failure reason.

The pipeline example looks like this:

python
from expression import pipe
from expression.collections import seq

total = pipe(
    [4, 7, 12, 15],
    seq.filter(lambda score: score >= 10),
    seq.map(lambda score: score * 2),
    seq.sum,
)

assert total == 54

Two things to notice. The functions are passed as bare names rather than as calls, so the pipeline reads as a list of transformations, and the module is seq rather than collections, with the import path expression.collections.seq. The collection module is where the day to day work happens, and the library expects you to learn it progressively: installation, then pipelines, optional values, expected failures, collections, and domain modelling.

The project is MIT licensed, published on PyPI as Expression with the readthedocs documentation, with the last release v5.7.0 in August 2026 and the last push on 2026-10-19.

Editorial conclusion

Expression fits a Python team that wants optional values and expected-failure results handled explicitly, or an F# developer who needs to work in Python without writing it as a translation, and who is willing to accept a type-annotated, Pylance-clean codebase. It does not fit a codebase that will not adopt annotations, or a team that wants a dependency-free way to model absence. Before adopting it, check that your project already passes strict static type checking, since the library sets that as a condition of use, and read the collection API before designing around it, because the seq module is where the day to day benefit lives and it has its own conventions.

Frequently asked questions

What is the Expression library for Python?

It is a MIT licensed library for pragmatic functional programming in Python 3.10 and later, taking F# as its reference rather than Haskell. It provides Option and Result types, pipeline and pipe friendly methods, a seq collection module and F# inspired abstractions, with the stated goal of code that still looks like Python.

How do I install Expression?

With `pip install expression`, and the library only works for Python 3.10 or newer. Pydantic v2 support is an extra, installed with `pip install expression[pydantic]`. The package is published on PyPI as Expression with the documentation on readthedocs.

What does Expression deliberately avoid and why?

It avoids currying, because Python does not support it by default and it is not a well known concept to Python programmers. It avoids overloading operators such as the pipe or the shift, because that usually confuses more than it helps. And it avoids recursion, which is not normally used in Python and should be hidden inside the library.

How do the pipelines in Expression look?

You pipe a value through a sequence of transformations, with the functions passed as bare names rather than calls, using pipe together with the seq module from expression.collections. The documented example filters, maps and sums a list of scores in a single pipe expression, and the library asks you to learn the API progressively from pipelines through to optional values, expected failures, collections and domain modelling.

What type checking does Expression expect?

It expects a codebase that passes strict static type checking with Pylance, provides type hints for all functions and methods, supports PEP 634 and structural pattern matching, and offers Pydantic friendly data types so Expression types can be used inside a Pydantic data model. The README's argument is that a strongly typed language makes refactoring much safer than where mypy and Pylance leave you wondering who is right.

Official sources

  1. dbrattli/Expression on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/dbrattli-expression.svg)](https://hysenlabs.com/projects/dbrattli-expression)

Was this useful?