morphir-python 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. morphir/__init__.py +14 -0
  2. morphir/ir/__init__.py +110 -0
  3. morphir/ir/access_controlled.py +15 -0
  4. morphir/ir/decorations.py +19 -0
  5. morphir/ir/diagnostics.py +105 -0
  6. morphir/ir/distribution.py +21 -0
  7. morphir/ir/document.py +37 -0
  8. morphir/ir/documented.py +11 -0
  9. morphir/ir/format_version.py +483 -0
  10. morphir/ir/fqname.py +9 -0
  11. morphir/ir/json.py +11 -0
  12. morphir/ir/literal.py +25 -0
  13. morphir/ir/meta.py +11 -0
  14. morphir/ir/migrate.py +1267 -0
  15. morphir/ir/module.py +17 -0
  16. morphir/ir/name.py +27 -0
  17. morphir/ir/package.py +15 -0
  18. morphir/ir/path.py +25 -0
  19. morphir/ir/qname.py +9 -0
  20. morphir/ir/ref.py +17 -0
  21. morphir/ir/type.py +37 -0
  22. morphir/ir/type_constraints.py +33 -0
  23. morphir/ir/type_def.py +19 -0
  24. morphir/ir/type_spec.py +25 -0
  25. morphir/ir/v3/__init__.py +64 -0
  26. morphir/ir/v3/_legacy_value.py +201 -0
  27. morphir/ir/v3/access_controlled.py +31 -0
  28. morphir/ir/v3/codec.py +1275 -0
  29. morphir/ir/v3/codec_v1.py +491 -0
  30. morphir/ir/v3/codec_v2.py +187 -0
  31. morphir/ir/v3/distribution.py +42 -0
  32. morphir/ir/v3/documented.py +13 -0
  33. morphir/ir/v3/fqname.py +30 -0
  34. morphir/ir/v3/literal.py +46 -0
  35. morphir/ir/v3/module.py +32 -0
  36. morphir/ir/v3/name.py +42 -0
  37. morphir/ir/v3/package.py +23 -0
  38. morphir/ir/v3/path.py +29 -0
  39. morphir/ir/v3/qname.py +16 -0
  40. morphir/ir/v3/type.py +126 -0
  41. morphir/ir/v3/value.py +235 -0
  42. morphir/ir/v4/__init__.py +160 -0
  43. morphir/ir/v4/access_controlled.py +17 -0
  44. morphir/ir/v4/annotation.py +75 -0
  45. morphir/ir/v4/codec.py +2161 -0
  46. morphir/ir/v4/decorations.py +88 -0
  47. morphir/ir/v4/distribution.py +56 -0
  48. morphir/ir/v4/document.py +69 -0
  49. morphir/ir/v4/documented.py +10 -0
  50. morphir/ir/v4/fqname.py +69 -0
  51. morphir/ir/v4/incompleteness.py +78 -0
  52. morphir/ir/v4/json.py +103 -0
  53. morphir/ir/v4/literal.py +51 -0
  54. morphir/ir/v4/meta.py +27 -0
  55. morphir/ir/v4/module.py +30 -0
  56. morphir/ir/v4/name.py +69 -0
  57. morphir/ir/v4/package.py +19 -0
  58. morphir/ir/v4/path.py +50 -0
  59. morphir/ir/v4/qname.py +34 -0
  60. morphir/ir/v4/ref.py +35 -0
  61. morphir/ir/v4/type.py +140 -0
  62. morphir/ir/v4/type_constraints.py +91 -0
  63. morphir/ir/v4/type_def.py +38 -0
  64. morphir/ir/v4/type_spec.py +64 -0
  65. morphir/ir/v4/value.py +480 -0
  66. morphir/ir/value.py +81 -0
  67. morphir/py.typed +0 -0
  68. morphir/sdk/__init__.py +110 -0
  69. morphir/sdk/_compare.py +187 -0
  70. morphir/sdk/aggregate.py +421 -0
  71. morphir/sdk/basics.py +504 -0
  72. morphir/sdk/char.py +110 -0
  73. morphir/sdk/decimal.py +311 -0
  74. morphir/sdk/dict.py +336 -0
  75. morphir/sdk/instant.py +118 -0
  76. morphir/sdk/int.py +86 -0
  77. morphir/sdk/key.py +522 -0
  78. morphir/sdk/list.py +356 -0
  79. morphir/sdk/local_date.py +436 -0
  80. morphir/sdk/local_time.py +267 -0
  81. morphir/sdk/maybe.py +135 -0
  82. morphir/sdk/number.py +237 -0
  83. morphir/sdk/regex.py +287 -0
  84. morphir/sdk/result.py +162 -0
  85. morphir/sdk/result_list.py +169 -0
  86. morphir/sdk/rule.py +103 -0
  87. morphir/sdk/set.py +214 -0
  88. morphir/sdk/stateful_app.py +49 -0
  89. morphir/sdk/string.py +427 -0
  90. morphir/sdk/tuple.py +43 -0
  91. morphir/sdk/uuid.py +209 -0
  92. morphir_python-0.0.1.dist-info/METADATA +269 -0
  93. morphir_python-0.0.1.dist-info/RECORD +99 -0
  94. morphir_python-0.0.1.dist-info/WHEEL +4 -0
  95. morphir_python-0.0.1.dist-info/entry_points.txt +2 -0
  96. morphir_python-0.0.1.dist-info/licenses/LICENSE +201 -0
  97. morphir_tools/__init__.py +13 -0
  98. morphir_tools/cli.py +223 -0
  99. morphir_tools/py.typed +0 -0
@@ -0,0 +1,42 @@
1
+ """V3 distributions (morphir-elm ``Morphir.IR.Distribution``).
2
+
3
+ Format 3.0.0 has only the ``Library`` distribution. Format 3.1.0 adds ``Specs``,
4
+ which publishes a package's specification without its definitions (finos/morphir
5
+ decision record 0018). Type attributes are unit (``None``) and value attributes
6
+ are the value's type. There is no package release version.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from dataclasses import dataclass, field
12
+
13
+ from . import package
14
+ from .path import Path
15
+ from .type import Type
16
+
17
+ type TypedValueAttributes = Type[None]
18
+
19
+
20
+ @dataclass(frozen=True)
21
+ class Library:
22
+ """A format-3 library: a package name, dependencies, and a definition."""
23
+
24
+ package_name: Path
25
+ definition: package.Definition[None, Type[None]]
26
+ dependencies: dict[Path, package.Specification[None]] = field(default_factory=dict)
27
+
28
+
29
+ @dataclass(frozen=True)
30
+ class Specs:
31
+ """A format-3.1.0 Specs distribution: a package's public face.
32
+
33
+ It has the shape of a `Library`, with a package specification in place of the
34
+ package definition. Writers declare ``formatVersion`` ``"3.1.0"`` for it.
35
+ """
36
+
37
+ package_name: Path
38
+ specification: package.Specification[None]
39
+ dependencies: dict[Path, package.Specification[None]] = field(default_factory=dict)
40
+
41
+
42
+ type Distribution = Library | Specs
@@ -0,0 +1,13 @@
1
+ """V3 documented values (morphir-elm ``Morphir.IR.Documented``)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+
7
+
8
+ @dataclass(frozen=True)
9
+ class Documented[T]:
10
+ """A value with documentation. In v3 the documentation is always a string."""
11
+
12
+ doc: str
13
+ value: T
@@ -0,0 +1,30 @@
1
+ """V3 fully qualified names (morphir-elm ``Morphir.IR.FQName``)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+
7
+ from . import name, path
8
+ from .name import Name
9
+ from .path import Path
10
+
11
+
12
+ @dataclass(frozen=True)
13
+ class FQName:
14
+ """A package path, a module path, and a local name."""
15
+
16
+ package_path: Path
17
+ module_path: Path
18
+ local_name: Name
19
+
20
+
21
+ def fqn(package: str, module: str, local: str) -> FQName:
22
+ """Build an FQName from strings, as elm ``FQName.fqn`` does.
23
+
24
+ Example:
25
+ >>> fqn("Morphir.SDK", "Basics", "Int").local_name
26
+ ('int',)
27
+ """
28
+ return FQName(
29
+ path.from_string(package), path.from_string(module), name.from_string(local)
30
+ )
@@ -0,0 +1,46 @@
1
+ """V3 literals (morphir-elm ``Morphir.IR.Literal``)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from decimal import Decimal
7
+
8
+
9
+ @dataclass(frozen=True)
10
+ class BoolLiteral:
11
+ value: bool
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class CharLiteral:
16
+ value: str
17
+
18
+
19
+ @dataclass(frozen=True)
20
+ class StringLiteral:
21
+ value: str
22
+
23
+
24
+ @dataclass(frozen=True)
25
+ class WholeNumberLiteral:
26
+ value: int
27
+
28
+
29
+ @dataclass(frozen=True)
30
+ class FloatLiteral:
31
+ value: float
32
+
33
+
34
+ @dataclass(frozen=True)
35
+ class DecimalLiteral:
36
+ value: Decimal
37
+
38
+
39
+ type Literal = (
40
+ BoolLiteral
41
+ | CharLiteral
42
+ | StringLiteral
43
+ | WholeNumberLiteral
44
+ | FloatLiteral
45
+ | DecimalLiteral
46
+ )
@@ -0,0 +1,32 @@
1
+ """V3 modules (morphir-elm ``Morphir.IR.Module``)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+
7
+ from . import type as t
8
+ from . import value as v
9
+ from .access_controlled import AccessControlled
10
+ from .documented import Documented
11
+ from .name import Name
12
+ from .path import Path
13
+
14
+ type ModuleName = Path
15
+
16
+
17
+ @dataclass(frozen=True)
18
+ class Specification[TA]:
19
+ types: dict[Name, Documented[t.Specification[TA]]] = field(default_factory=dict)
20
+ values: dict[Name, Documented[v.Specification[TA]]] = field(default_factory=dict)
21
+ doc: str | None = None
22
+
23
+
24
+ @dataclass(frozen=True)
25
+ class Definition[TA, VA]:
26
+ types: dict[Name, AccessControlled[Documented[t.Definition[TA]]]] = field(
27
+ default_factory=dict
28
+ )
29
+ values: dict[Name, AccessControlled[Documented[v.Definition[TA, VA]]]] = field(
30
+ default_factory=dict
31
+ )
32
+ doc: str | None = None
morphir/ir/v3/name.py ADDED
@@ -0,0 +1,42 @@
1
+ """V3 names: lists of lowercase words (morphir-elm ``Morphir.IR.Name``)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+
7
+
8
+ class Name(tuple[str, ...]):
9
+ """A v3 name such as ``["value", "in", "u", "s", "d"]``.
10
+
11
+ Distinct from `morphir.ir.v4.Name` so that a type checker catches mixing.
12
+ """
13
+
14
+ __slots__ = ()
15
+
16
+
17
+ def from_list(words: list[str] | tuple[str, ...]) -> Name:
18
+ """Build a name from words, as elm ``Name.fromList`` does."""
19
+ return Name(tuple(words))
20
+
21
+
22
+ def to_list(name: Name) -> list[str]:
23
+ """Return the words of a name."""
24
+ return list(name)
25
+
26
+
27
+ def from_string(text: str) -> Name:
28
+ """Split text into lowercase words, as elm ``Name.fromString`` does.
29
+
30
+ Example:
31
+ >>> from_string("valueInUSD")
32
+ ('value', 'in', 'u', 's', 'd')
33
+ """
34
+ words = re.findall(r"[a-zA-Z][a-z]*|[0-9]+", text)
35
+ return Name(tuple(word.lower() for word in words))
36
+
37
+
38
+ def to_camel_case(name: Name) -> str:
39
+ """Render as camelCase, as elm ``Name.toCamelCase`` does."""
40
+ if not name:
41
+ return ""
42
+ return name[0] + "".join(word.capitalize() for word in name[1:])
@@ -0,0 +1,23 @@
1
+ """V3 packages (morphir-elm ``Morphir.IR.Package``)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+
7
+ from . import module
8
+ from .access_controlled import AccessControlled
9
+ from .path import Path
10
+
11
+ type PackageName = Path
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class Specification[TA]:
16
+ modules: dict[Path, module.Specification[TA]] = field(default_factory=dict)
17
+
18
+
19
+ @dataclass(frozen=True)
20
+ class Definition[TA, VA]:
21
+ modules: dict[Path, AccessControlled[module.Definition[TA, VA]]] = field(
22
+ default_factory=dict
23
+ )
morphir/ir/v3/path.py ADDED
@@ -0,0 +1,29 @@
1
+ """V3 paths: lists of names (morphir-elm ``Morphir.IR.Path``)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from .name import Name
6
+ from .name import from_string as name_from_string
7
+
8
+
9
+ class Path(tuple[Name, ...]):
10
+ """A v3 path such as ``[["morphir"], ["s", "d", "k"]]``."""
11
+
12
+ __slots__ = ()
13
+
14
+
15
+ def from_list(names: list[Name] | tuple[Name, ...]) -> Path:
16
+ """Build a path from names."""
17
+ return Path(tuple(names))
18
+
19
+
20
+ def to_list(path: Path) -> list[Name]:
21
+ """Return the names of a path."""
22
+ return list(path)
23
+
24
+
25
+ def from_string(text: str) -> Path:
26
+ """Split ``Morphir.SDK`` or ``morphir/sdk`` into a path of names."""
27
+ import re
28
+
29
+ return Path(tuple(name_from_string(p) for p in re.split(r"[./]", text) if p))
morphir/ir/v3/qname.py ADDED
@@ -0,0 +1,16 @@
1
+ """V3 qualified names (morphir-elm ``Morphir.IR.QName``)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+
7
+ from .name import Name
8
+ from .path import Path
9
+
10
+
11
+ @dataclass(frozen=True)
12
+ class QName:
13
+ """A module path and a local name."""
14
+
15
+ module_path: Path
16
+ local_name: Name
morphir/ir/v3/type.py ADDED
@@ -0,0 +1,126 @@
1
+ """V3 types (morphir-elm ``Morphir.IR.Type``).
2
+
3
+ Every node is parameterized by its attribute type ``A``. A distribution fixes
4
+ ``A`` to ``None``, which is elm's unit ``()``.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass
10
+
11
+ from .access_controlled import AccessControlled
12
+ from .fqname import FQName
13
+ from .name import Name
14
+
15
+
16
+ @dataclass(frozen=True)
17
+ class Variable[A]:
18
+ attributes: A
19
+ name: Name
20
+
21
+
22
+ @dataclass(frozen=True)
23
+ class Reference[A]:
24
+ attributes: A
25
+ fqname: FQName
26
+ args: tuple[Type[A], ...] = ()
27
+
28
+
29
+ @dataclass(frozen=True)
30
+ class Tuple[A]:
31
+ attributes: A
32
+ elements: tuple[Type[A], ...] = ()
33
+
34
+
35
+ @dataclass(frozen=True)
36
+ class Record[A]:
37
+ attributes: A
38
+ fields: tuple[Field[A], ...] = ()
39
+
40
+
41
+ @dataclass(frozen=True)
42
+ class ExtensibleRecord[A]:
43
+ attributes: A
44
+ variable: Name
45
+ fields: tuple[Field[A], ...] = ()
46
+
47
+
48
+ @dataclass(frozen=True)
49
+ class Function[A]:
50
+ attributes: A
51
+ argument_type: Type[A]
52
+ return_type: Type[A]
53
+
54
+
55
+ @dataclass(frozen=True)
56
+ class Unit[A]:
57
+ attributes: A
58
+
59
+
60
+ type Type[A] = (
61
+ Variable[A]
62
+ | Reference[A]
63
+ | Tuple[A]
64
+ | Record[A]
65
+ | ExtensibleRecord[A]
66
+ | Function[A]
67
+ | Unit[A]
68
+ )
69
+
70
+
71
+ @dataclass(frozen=True)
72
+ class Field[A]:
73
+ name: Name
74
+ tpe: Type[A]
75
+
76
+
77
+ type ConstructorArgs[A] = tuple[tuple[Name, Type[A]], ...]
78
+ type Constructors[A] = dict[Name, ConstructorArgs[A]]
79
+
80
+
81
+ @dataclass(frozen=True)
82
+ class TypeAliasSpecification[A]:
83
+ type_params: tuple[Name, ...]
84
+ tpe: Type[A]
85
+
86
+
87
+ @dataclass(frozen=True)
88
+ class OpaqueTypeSpecification:
89
+ type_params: tuple[Name, ...]
90
+
91
+
92
+ @dataclass(frozen=True)
93
+ class CustomTypeSpecification[A]:
94
+ type_params: tuple[Name, ...]
95
+ constructors: Constructors[A]
96
+
97
+
98
+ @dataclass(frozen=True)
99
+ class DerivedTypeSpecification[A]:
100
+ type_params: tuple[Name, ...]
101
+ base_type: Type[A]
102
+ from_base_type: FQName
103
+ to_base_type: FQName
104
+
105
+
106
+ type Specification[A] = (
107
+ TypeAliasSpecification[A]
108
+ | OpaqueTypeSpecification
109
+ | CustomTypeSpecification[A]
110
+ | DerivedTypeSpecification[A]
111
+ )
112
+
113
+
114
+ @dataclass(frozen=True)
115
+ class TypeAliasDefinition[A]:
116
+ type_params: tuple[Name, ...]
117
+ tpe: Type[A]
118
+
119
+
120
+ @dataclass(frozen=True)
121
+ class CustomTypeDefinition[A]:
122
+ type_params: tuple[Name, ...]
123
+ constructors: AccessControlled[Constructors[A]]
124
+
125
+
126
+ type Definition[A] = TypeAliasDefinition[A] | CustomTypeDefinition[A]
morphir/ir/v3/value.py ADDED
@@ -0,0 +1,235 @@
1
+ """V3 values and patterns (morphir-elm ``Morphir.IR.Value``).
2
+
3
+ Values take two attribute parameters, as in elm: ``TA`` for the types inside
4
+ definitions and ``VA`` for value and pattern nodes. A distribution fixes ``TA`` to
5
+ ``None`` and ``VA`` to ``Type[None]``.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass
11
+
12
+ from .fqname import FQName
13
+ from .literal import Literal
14
+ from .name import Name
15
+ from .type import Type
16
+
17
+ # --- Patterns ---
18
+
19
+
20
+ @dataclass(frozen=True)
21
+ class WildcardPattern[A]:
22
+ attributes: A
23
+
24
+
25
+ @dataclass(frozen=True)
26
+ class AsPattern[A]:
27
+ attributes: A
28
+ pattern: Pattern[A]
29
+ name: Name
30
+
31
+
32
+ @dataclass(frozen=True)
33
+ class TuplePattern[A]:
34
+ attributes: A
35
+ elements: tuple[Pattern[A], ...]
36
+
37
+
38
+ @dataclass(frozen=True)
39
+ class ConstructorPattern[A]:
40
+ attributes: A
41
+ constructor: FQName
42
+ args: tuple[Pattern[A], ...]
43
+
44
+
45
+ @dataclass(frozen=True)
46
+ class EmptyListPattern[A]:
47
+ attributes: A
48
+
49
+
50
+ @dataclass(frozen=True)
51
+ class HeadTailPattern[A]:
52
+ attributes: A
53
+ head: Pattern[A]
54
+ tail: Pattern[A]
55
+
56
+
57
+ @dataclass(frozen=True)
58
+ class LiteralPattern[A]:
59
+ attributes: A
60
+ literal: Literal
61
+
62
+
63
+ @dataclass(frozen=True)
64
+ class UnitPattern[A]:
65
+ attributes: A
66
+
67
+
68
+ type Pattern[A] = (
69
+ WildcardPattern[A]
70
+ | AsPattern[A]
71
+ | TuplePattern[A]
72
+ | ConstructorPattern[A]
73
+ | EmptyListPattern[A]
74
+ | HeadTailPattern[A]
75
+ | LiteralPattern[A]
76
+ | UnitPattern[A]
77
+ )
78
+
79
+ # --- Values ---
80
+
81
+
82
+ @dataclass(frozen=True)
83
+ class LiteralValue[TA, VA]:
84
+ attributes: VA
85
+ literal: Literal
86
+
87
+
88
+ @dataclass(frozen=True)
89
+ class Constructor[TA, VA]:
90
+ attributes: VA
91
+ fqname: FQName
92
+
93
+
94
+ @dataclass(frozen=True)
95
+ class Tuple[TA, VA]:
96
+ attributes: VA
97
+ elements: tuple[Value[TA, VA], ...]
98
+
99
+
100
+ @dataclass(frozen=True)
101
+ class List[TA, VA]:
102
+ attributes: VA
103
+ items: tuple[Value[TA, VA], ...]
104
+
105
+
106
+ @dataclass(frozen=True)
107
+ class Record[TA, VA]:
108
+ attributes: VA
109
+ fields: dict[Name, Value[TA, VA]]
110
+
111
+
112
+ @dataclass(frozen=True)
113
+ class Variable[TA, VA]:
114
+ attributes: VA
115
+ name: Name
116
+
117
+
118
+ @dataclass(frozen=True)
119
+ class Reference[TA, VA]:
120
+ attributes: VA
121
+ fqname: FQName
122
+
123
+
124
+ @dataclass(frozen=True)
125
+ class Field[TA, VA]:
126
+ attributes: VA
127
+ subject: Value[TA, VA]
128
+ field_name: Name
129
+
130
+
131
+ @dataclass(frozen=True)
132
+ class FieldFunction[TA, VA]:
133
+ attributes: VA
134
+ name: Name
135
+
136
+
137
+ @dataclass(frozen=True)
138
+ class Apply[TA, VA]:
139
+ attributes: VA
140
+ function: Value[TA, VA]
141
+ argument: Value[TA, VA]
142
+
143
+
144
+ @dataclass(frozen=True)
145
+ class Lambda[TA, VA]:
146
+ attributes: VA
147
+ pattern: Pattern[VA]
148
+ body: Value[TA, VA]
149
+
150
+
151
+ @dataclass(frozen=True)
152
+ class LetDefinition[TA, VA]:
153
+ attributes: VA
154
+ name: Name
155
+ definition: Definition[TA, VA]
156
+ in_value: Value[TA, VA]
157
+
158
+
159
+ @dataclass(frozen=True)
160
+ class LetRecursion[TA, VA]:
161
+ attributes: VA
162
+ definitions: dict[Name, Definition[TA, VA]]
163
+ in_value: Value[TA, VA]
164
+
165
+
166
+ @dataclass(frozen=True)
167
+ class Destructure[TA, VA]:
168
+ attributes: VA
169
+ pattern: Pattern[VA]
170
+ value_to_destructure: Value[TA, VA]
171
+ in_value: Value[TA, VA]
172
+
173
+
174
+ @dataclass(frozen=True)
175
+ class IfThenElse[TA, VA]:
176
+ attributes: VA
177
+ condition: Value[TA, VA]
178
+ then_branch: Value[TA, VA]
179
+ else_branch: Value[TA, VA]
180
+
181
+
182
+ @dataclass(frozen=True)
183
+ class PatternMatch[TA, VA]:
184
+ attributes: VA
185
+ branch_on: Value[TA, VA]
186
+ cases: tuple[tuple[Pattern[VA], Value[TA, VA]], ...]
187
+
188
+
189
+ @dataclass(frozen=True)
190
+ class UpdateRecord[TA, VA]:
191
+ attributes: VA
192
+ value_to_update: Value[TA, VA]
193
+ fields: dict[Name, Value[TA, VA]]
194
+
195
+
196
+ @dataclass(frozen=True)
197
+ class Unit[TA, VA]:
198
+ attributes: VA
199
+
200
+
201
+ type Value[TA, VA] = (
202
+ LiteralValue[TA, VA]
203
+ | Constructor[TA, VA]
204
+ | Tuple[TA, VA]
205
+ | List[TA, VA]
206
+ | Record[TA, VA]
207
+ | Variable[TA, VA]
208
+ | Reference[TA, VA]
209
+ | Field[TA, VA]
210
+ | FieldFunction[TA, VA]
211
+ | Apply[TA, VA]
212
+ | Lambda[TA, VA]
213
+ | LetDefinition[TA, VA]
214
+ | LetRecursion[TA, VA]
215
+ | Destructure[TA, VA]
216
+ | IfThenElse[TA, VA]
217
+ | PatternMatch[TA, VA]
218
+ | UpdateRecord[TA, VA]
219
+ | Unit[TA, VA]
220
+ )
221
+
222
+ # --- Specifications and definitions ---
223
+
224
+
225
+ @dataclass(frozen=True)
226
+ class Specification[TA]:
227
+ inputs: tuple[tuple[Name, Type[TA]], ...]
228
+ output: Type[TA]
229
+
230
+
231
+ @dataclass(frozen=True)
232
+ class Definition[TA, VA]:
233
+ input_types: tuple[tuple[Name, VA, Type[TA]], ...]
234
+ output_type: Type[TA]
235
+ body: Value[TA, VA]