Skip to content

Commit

Permalink
Built-in Tuple and Unit types.
Browse files Browse the repository at this point in the history
This means that the user can always write `A * B * C` for the type of
tuples `(a, b, c)` of values of those respective types.

This is a quick implementation for issue #78. Parsing is not yet
implemented!
  • Loading branch information
nsbgn committed Mar 11, 2022
1 parent a9ca3d3 commit 14bb6f6
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 14 deletions.
17 changes: 12 additions & 5 deletions transformation_algebra/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from __future__ import annotations

from transformation_algebra.type import Type, TypeOperation, TypeVariable, \
Function, TypeInstance
Function, Tuple, Unit, TypeInstance
from transformation_algebra.expr import \
Expr, Operation, Application, Abstraction, Source
from transformation_algebra.lang import Language
Expand Down Expand Up @@ -67,7 +67,7 @@ def default(switch: bool | None) -> bool:

for t in self.language.taxonomy:
self.type_nodes[t] = self.language.namespace[
t.text(sep=".", lparen="_", rparen="")]
t.text(sep=".", lparen="_", rparen="", prod="")]

self.bind("ta", TA)
self.bind("lang", self.language.namespace)
Expand Down Expand Up @@ -107,6 +107,7 @@ def add_taxonomy(self) -> None:
for root in set(taxonomy) - set.union(*taxonomy.values()):
if root._operator.arity > 0:
self.add((self.type_nodes[root], RDFS.subClassOf,
TA.Tuple if root._operator is Tuple else
self.language.namespace[root._operator.name]))

if self.with_transitive_closure:
Expand Down Expand Up @@ -143,8 +144,11 @@ def add_type(self, type: Type) -> Node:
if isinstance(t, TypeOperation):
if t.params:
node = BNode()
self.add((node, RDFS.subClassOf,
self.language.namespace[t._operator.name]))
if t._operator is Tuple:
self.add((node, RDFS.subClassOf, TA.Tuple))
else:
self.add((node, RDFS.subClassOf,
self.language.namespace[t._operator.name]))

if self.with_type_parameters:
for i, param in enumerate(t.params, start=1):
Expand All @@ -153,7 +157,10 @@ def add_type(self, type: Type) -> Node:
if self.with_labels:
self.add((node, RDFS.label, Literal(str(t))))
else:
node = self.language.namespace[t._operator.name]
if t._operator is Unit:
node = TA.Unit
else:
node = self.language.namespace[t._operator.name]
else:
assert isinstance(t, TypeVariable)
node = BNode()
Expand Down
7 changes: 5 additions & 2 deletions transformation_algebra/lang.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ def generate_taxonomy(self) -> Taxonomy:
# taxonomy; if it is not, we handle it before going forward
for p in t.params:
if p not in taxonomy:
assert isinstance(p, TypeOperation)
stack.append(t)
stack.append(p)
break
Expand Down Expand Up @@ -317,7 +318,8 @@ def __new__(cls, uri, lang: Language):
terms = chain(
lang.operators.keys(),
lang.types.keys(),
(t.text(sep=".", lparen="_", rparen="") for t in lang.taxonomy)
(t.text(sep=".", lparen="_", rparen="", prod="")
for t in lang.taxonomy)
)
rt = super().__new__(cls, uri, terms)
cls.lang = lang
Expand All @@ -328,7 +330,8 @@ def term(self, value) -> URIRef:
return super().term(value.name)
elif isinstance(value, TypeOperation):
assert value in self.lang.taxonomy
return super().term(value.text(sep=".", lparen="_", rparen=""))
return super().term(value.text(sep=".", lparen="_", rparen="",
prod=""))
else:
return super().term(value)

Expand Down
27 changes: 22 additions & 5 deletions transformation_algebra/type.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ def __rpow__(self, other: Type | tuple[Type]) -> TypeInstance:
else:
return other.__pow__(self)

def __mul__(self, other: Type) -> TypeInstance:
"""
Tuple operator.
"""
# See issue #78
return Tuple(self.instance(), other.instance())

def __lt__(self, other: Type) -> Optional[bool]:
a, b = self.instance(), other.instance()
return not a.match(b) and a <= b
Expand Down Expand Up @@ -223,22 +230,26 @@ def text(self,
sep: str = ", ",
lparen: str = "(",
rparen: str = ")",
arrow: str = "→",
arrow: str = " → ",
prod: str = " × ",
with_constraints: bool = False) -> str:
"""
Convert the given type to a textual representation.
"""

args = labels, sep, lparen, rparen, arrow
args = labels, sep, lparen, rparen, arrow, prod

if isinstance(self, TypeOperation):
if self._operator == Function:
i, o = self.params
if isinstance(i, TypeOperation) and i._operator == Function:
result = f"{lparen}{i.text(*args)}{rparen} " \
f"{arrow} {o.text(*args)}"
result = f"{lparen}{i.text(*args)}{rparen}" \
f"{arrow}{o.text(*args)}"
else:
result = f"{i.text(*args)} {arrow} {o.text(*args)}"
result = f"{i.text(*args)}{arrow}{o.text(*args)}"
elif self._operator == Tuple and prod:
a, b = self.params
result = f"{lparen}{a.text(*args)}{prod}{b.text(*args)}{rparen}"
else:
if self.params:
result = f"{self._operator}{lparen}" \
Expand Down Expand Up @@ -810,6 +821,12 @@ def fulfilled(self) -> bool:
"The special constructor for function types."
Function = TypeOperator('Function', params=[Variance.CONTRA, Variance.CO])

"The special constructor for tuple types."
Tuple = TypeOperator('Tuple', params=2)

"The special constructor for the unit type."
Unit = TypeOperator('Unit')

"A wildcard: fresh variable, unrelated to, and matchable with, anything else."
_ = TypeSchema(lambda: TypeVariable(wildcard=True))

Expand Down
11 changes: 9 additions & 2 deletions vocab/transformation-algebra.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@
rdfs:comment "The class of all transformation types.".

:Function
a rdfs:Class;
rdfs:subClassOf :Type;
a rdfs:Class; rdfs:subClassOf :Type;
rdfs:comment "The class of function types.".

:Tuple
a rdfs:Class; rdfs:subClassOf :Type;
rdfs:comment "The class of tuple types.".

:Unit
a rdfs:Class; rdfs:subClassOf :Type;
rdfs:comment "The unit type, containing only a single value.".

0 comments on commit 14bb6f6

Please sign in to comment.