Type inference for transformation algebras.
Project description
transformation-algebra
A transformation algebra describes abstract transformations of tools in some domain. An expression of such an algebra should have an interpretation, but there is not necessarily any concrete data structure or implementation assigned to it. The algebra simply describes what type of data some tool can take, and what type of data it produces.
To define such an algebra, we implemented a type inference system in Python. The system accepts subtypes. To make it work, some magic happens under the hood; for now, refer to the source code to gain a deeper understanding. This document is merely intended to be a user's guide.
Concrete types and subtypes
We first need to declare some bacic type signatures. For this, we use the
Operator class.
>>> from transformation_algebra.type import Operator
>>> Any = Operator("Any")
Basic types may have supertypes. For instance, anything of type Int is also
automatically of type Any, but not necessarily of type UInt:
>>> Int = Operator("Int", supertype=Any)
>>> UInt = Operator("UInt", supertype=Int)
>>> Int <= Any
True
>>> Int <= UInt
False
Higher-order types take other types as parameters, allowing us to combine
types. For example, Set(Int) could represent a set of integers. Note that
this is automatically a subtype of Set(Any).
>>> Set = Operator("Set", 1)
>>> Set(Int) <= Set(Any)
True
A special higher-order type is Function, which describes a transformation.
For convenience, to create functions, the right-associative infix operator
** has been overloaded, resembling the function arrow. A function that takes
multiple types can be rewritten to a
sequence of functions.
>>> add = Int ** Int ** Int
>>> abs = Int ** UInt
When we apply an input type to a function signature, we get its output type, or, if the type was inappropriate, an error:
>>> add(Int, UInt)
Int
>>> add(Any)
...
Subtype mismatch. Could not satisfy:
Any <= Int
Schematic types and constraints
Our types are polymorphic in that any type also represents its supertypes:
the signature Int ** Int also applies to UInt ** Int or indeed to Int ** Any. We additionally allow parametric polymorphism, using the Schema
class.
>>> from transformation_algebra.type import Schema
>>> compose = Schema(lambda α, β, γ: (β ** γ) ** (α ** β) ** (α ** γ))
>>> compose(abs, add(Int))
Int ** UInt
Don't be fooled by the lambda keyword --- this is an implementation artefact
and does not refer to lambda abstraction. Instead, the Schema is initialized
with an anonymous Python function, its parameters declaring the variables that
occur in its body, akin to quantifying those variables. When instantiating
the schema, these variables are automatically populated.
Note that, when you need a variable but you don't care about what variable it
is or how it relates to others, you may use the _ wildcard variable.
>>> from transformation_algebra.type import _
>>> size = Set(_) ** Int
Often, variables in a schema are not universally quantified, but constrained
to some typeclass. We can use the t | c operator to attach a typeclass
constraint c to a term t. c can then specify the typeclass in an ad-hoc
manner, using the t @ [ts] operator (meaning that a term t must be a
subtype of one of the types specified in [ts]). For instance, we might want
to define a function that applies to both single integers and sets of
integers:
>>> sum = Schema(lambda α: α ** α | α @ [Int, Set(Int)])
>>> sum(Set(UInt))
Set(UInt)
Finally, operators is a helper function for specifying typeclasses: it
generates type terms that contain certain parameters.
>>> Map = Operator("Map", 2)
>>> operators(Map, param=Int)
[Map(Int, _), Map(_, Int)]
Algebra and expressions
Once we have created our types, we may define the TransformationAlgebra that
will read expressions of the algebra.
>>> from transformation_algebra.expr import TransformationAlgebra
>>> algebra = TransformationAlgebra(
number=Int,
abs=Int ** UInt,
...
)
In fact, for convenience, you may simply define your types as globals and automatically create the algebra once you are done:
>>> algebra = TransformationAlgebra.from_dict(globals())
At this point, we can parse strings using algebra.parse. The parser accepts
the names of any function and input type. Adjacent expressions are applied to
eachother and the parser will only succeed if the result typechecks. Input
types can take an optional identifier to label that input.
>>> algebra.parse("abs (number x)")
This will give you an Expr object, which has a type and sub-expressions.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file transformation_algebra-0.0.2.tar.gz.
File metadata
- Download URL: transformation_algebra-0.0.2.tar.gz
- Upload date:
- Size: 13.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.3.0 pkginfo/1.7.0 requests/2.22.0 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.36.1 CPython/3.7.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f4900ebd9a1f69382818f86be6b99e6a3254cb7dbf277b48c7feee0bd3487aaf
|
|
| MD5 |
4ed949647d171e5d63cec14e7f5e8df0
|
|
| BLAKE2b-256 |
a3537ce590ebf7122ca50d3c57392d010b090eb9e761016b7002bb2b01ae332a
|
File details
Details for the file transformation_algebra-0.0.2-py3-none-any.whl.
File metadata
- Download URL: transformation_algebra-0.0.2-py3-none-any.whl
- Upload date:
- Size: 24.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.3.0 pkginfo/1.7.0 requests/2.22.0 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.36.1 CPython/3.7.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8fdbf33dcb24284f936828c32a10d51ec5ebb3f9300cf8dfe723344e8fe6c58e
|
|
| MD5 |
e45214dff747e0352ddc3f748fcad754
|
|
| BLAKE2b-256 |
6c6a3e0697c37e30a15f9899756103a4972a6760701bc48e25a3bbdedfe4f84e
|