Skip to main content

Algebraic Data Types via Class Decorators

Project description

Overview

This package provides class-decorators for defining Algebraic Data Types (ADTs).

ADTs are mostly known from

  • functional languages such as Haskell or OCaml; and
  • Rust, where they are called enums.

Working with ADTs is most pleasant in the presence of pattern matching, so we recommend to use Python >= 3.10.

This package exports exactly two definitions:

  • the adt decorator introduces the constructor classes in the namespace of the decorated class; and
  • the adt_export decorator introduces the constructor classes in the global namespace.

Related packages

There are a few packages which aim to provide similar functionality:

  • algebraic-data-types also describes ADTs via class decorators and annotations, but is aimed at older python version and does not work with pattern matching.

  • algebraic-data-type does not support a concise definition via decorators.

Example

The following example defines the syntax tree for the lambda calculus as an ADT Expr together with a __str__-method, which pretty prints the syntax tree.

from adt import adt

@adt
class Expr:
    Var: str                          # Constructor with one unnamed argument
    Abs: [str, 'Expr']                # Constructor with two unnamed arguments
    App: {'e1': 'Expr', 'e2': 'Expr'} # Constructor with two named arguments

    def __str__(self) -> str:
        match self:
            case Expr.Var(x):      return x
            case Expr.Abs(x, e):   return f"(λ{x}. {e})"
            case Expr.App(e1, e2): return f"({e1} {e2})"

id_expr = Expr.Abs("x", Expr.Var("x"))

assert str(id_expr) == '(λx. x)'

As we used adt instead of adt_export, the constructors Var, Abs, and App are defined in the namespace of the base class Expr, and hence have to be accessed as Expr.Var, Expr.Abs, Expr.App.

The code generated by the adt decorator in the above example is equivalent to:

from dataclasses import dataclass

class Expr:
    def __init__(self, *args, **kwargs):
        raise TypeError(
            "Tried to construct an ADT instead of one of it's constructors.")
    
    def __str__(self) -> str:
        match self:
            case Expr.Var(x):      return x
            case Expr.Abs(x, e):   return f"(λ{x}. {e})"
            case Expr.App(e1, e2): return f"({e1} {e2})"

    def is_var(self) -> bool:
        return isinstance(self, Var)

    def is_abs(self) -> bool:
        return isinstance(self, Abs)

    def is_app(self) -> bool:
        return isinstance(self, App)

@dataclass
class Var(Expr):
  _1: str

@dataclass
class Abs(Expr):
  _1: str
  _2: 'Expr'

@dataclass
class App(Expr):
  e1: str
  e2: 'Expr'

# Those statements are not really executed, as the `Var`, `Abs` and
# `App` classes are created anonymously, so in the real implementation
# the global namespace is *not* even temporarily polluted.
Expr.Var = Var
Expr.Abs = Abs
Expr.App = App
del Var
del Abs
del App

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

adt-decorators-0.1.0.tar.gz (4.4 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page