Skip to content

Commit 10f2c42

Browse files
author
jared
committed
Added Typeclass quickstart
1 parent 71affa5 commit 10f2c42

File tree

1 file changed

+37
-20
lines changed

1 file changed

+37
-20
lines changed

docs/typescript.md

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,14 @@ autogen/LambdaBuffers/Document.mts
6767
autogen/build.json
6868
```
6969

70-
The generated `autogen` directory created contains the generated TypeScript modules.
70+
The generated `autogen` directory created contains the generated Typescript modules.
7171

7272
Note that `lbf-list-modules-typescript` is needed to create a JSON object which maps package names (for NPM) to Lambda Buffers' modules.
7373
Thus, in this example, one should have a `package.json` file which associates the key `"name"` with the string value `"lbf-document"`.
7474

7575
The `autogen/build.json` file can be ignored.
7676

77-
The file `autogen/LambdaBuffers/Document.mts` contains the outputted TypeScript module:
77+
The file `autogen/LambdaBuffers/Document.mts` contains the outputted Typescript module:
7878

7979
```ts
8080
// @ts-nocheck
@@ -113,7 +113,7 @@ export const RichDocument : unique symbol = Symbol('RichDocument')
113113
## Product types
114114
The type `RichDocument` have been declared as a product type in the LambdaBuffers schema using the `prod` keyword.
115115

116-
In general, product types are mapped to [tuple types](https://www.typescriptlang.org/docs/handbook/2/objects.html#tuple-types) in TypeScript most of the time. The exception is if there is only one element in the tuple in which case the type is translated to a type alias.
116+
In general, product types are mapped to [tuple types](https://www.typescriptlang.org/docs/handbook/2/objects.html#tuple-types) in Typescript most of the time. The exception is if there is only one element in the tuple in which case the type is translated to a type alias.
117117

118118
More precisely, given a LambdaBuffers' product type as follows
119119

@@ -123,21 +123,21 @@ prod MyProduct = SomeType1 ... SomeTypeN
123123

124124
where the `...` denotes iterated `SomeTypei` for some `i`, then
125125

126-
- If `N = 0` so `prod MyProduct =`, then we map this to the TypeScript type
126+
- If `N = 0` so `prod MyProduct =`, then we map this to the Typescript type
127127

128128
```ts
129129
export type MyProduct = []
130130
```
131131
132-
- If `N = 1` so `prod MyProduct = SomeType1`, then we map this to the TypeScript type
132+
- If `N = 1` so `prod MyProduct = SomeType1`, then we map this to the Typescript type
133133
134134
```ts
135135
export type MyProduct = SomeType1
136136
```
137137
138138
i.e., `MyProduct` simply aliases `SomeType1`
139139
140-
- If `N >= 2` so `prod MyProduct = SomeType1 ... SomeTypeN`, then we map this to the TypeScript type
140+
- If `N >= 2` so `prod MyProduct = SomeType1 ... SomeTypeN`, then we map this to the Typescript type
141141
142142
```ts
143143
export type MyProduct = [SomeType1, ..., SomeTypeN]
@@ -148,7 +148,7 @@ where the `...` denotes iterated `SomeTypei` for some `i`, then
148148
## Sum types
149149
The types `Author`, `Reviewer`, and `RichContent` have been declared as sum types in the LambdaBuffers schema using the `sum` keyword.
150150
151-
In general, sum types are mapped to a [union type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types) in TypeScript and with the additional following rules.
151+
In general, sum types are mapped to a [union type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types) in Typescript and with the additional following rules.
152152
Given a LambdaBuffers' sum type as follows
153153
154154
```purescript
@@ -160,13 +160,13 @@ sum MySum
160160
161161
where the `...` denotes either an iterated `Branchi` for some `i`, or an iterated `BranchiTypej` for some `i` and `j`, then each branch, say `Branchi` is translated as follows.
162162
163-
- If `Branchi` has no fields i.e., `| Branchi`, then the corresponding TypeScript type's union member is
163+
- If `Branchi` has no fields i.e., `| Branchi`, then the corresponding Typescript type's union member is
164164
165165
```ts
166166
| { name: 'Branchi' }
167167
```
168168
169-
- If `Branchi` has one or more fields i.e., `| Branchi BranchiType1 ... BranchiTypeMi`, then the corresponding TypeScript type's union member is
169+
- If `Branchi` has one or more fields i.e., `| Branchi BranchiType1 ... BranchiTypeMi`, then the corresponding Typescript type's union member is
170170
171171
```ts
172172
| { name: 'Branchi'
@@ -176,7 +176,7 @@ where the `...` denotes either an iterated `Branchi` for some `i`, or an iterate
176176
177177
where `<Product translation of BranchiType1 ... BranchiTypeMi>` denotes the right hand side of the [product translation](#product-types) of `prod FieldsProduct = BranchiType1 ... BranchiTypeMi`.
178178
179-
So, for example, given `| Branchi BranchiType1`, the corresponding TypeScript type is as follows
179+
So, for example, given `| Branchi BranchiType1`, the corresponding Typescript type is as follows
180180
181181
```ts
182182
| { name: 'Branchi'
@@ -195,24 +195,41 @@ where the `...` denotes either an iterated `Branchi` for some `i`, or an iterate
195195
## Record types
196196
The types `Document` and `Chapter` have been declared as record types in the LambdaBuffers schema using the `record` keyword.
197197
198-
Record types are mapped to [object types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#object-types) in TypeScript.
198+
Record types are mapped to [object types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#object-types) in Typescript.
199199
Given a LambdaBuffers' record type as follows
200200
201201
```purescript
202202
record MyRecord = { field1: SomeType1, ..., fieldN: SomeTypeN }
203203
```
204204
205-
where `...` denotes iterated `fieldi: SomeTypei` for some `i`, the corresponding TypeScript type is
205+
where `...` denotes iterated `fieldi: SomeTypei` for some `i`, the corresponding Typescript type is
206206
207207
```ts
208208
type MyRecord = { field1: SomeType1, ..., fieldN, SomeTypeN }
209209
```
210210
211-
## Type classes
212-
TypeScript has no builtin implementation of type classes. As such, LambdaBuffers rolled its own type classes.
213-
A complete usage example can be found in the [TypeScript Prelude sample project](./typescript-prelude/src/index.mts).
211+
## Type classes quickstart
214212
215-
A type class in TypeScript is an object type which defines a set of methods.
213+
Typescript has no builtin implementation of type classes. As such, LambdaBuffers rolled its own type classes.
214+
A complete usage example can be found in the [Typescript Prelude sample project](./typescript-prelude/src/index.mts), but assuming the packaging is setup correctly, the interface to use a typeclass is as follows
215+
216+
```ts
217+
import * as LbrPrelude from "lbr-prelude";
218+
219+
// In Haskell, this is `10 == 11`
220+
LbrPrelude.Eq[LbrPrelude.Integer].eq(10n, 11n) // false
221+
222+
// In Haskell, this is `Just 3 == Nothing`
223+
LbrPrelude.Eq[LbrPrelude.Maybe](LbrPrelude.Eq[LbrPrelude.Integer])
224+
.eq( { name: 'Just', fields: 3 }
225+
, { name: 'Nothing' }) // false
226+
```
227+
228+
In particular, we access a global variable `LbrPrelude.Eq` which contains the type class instances, and pick out a particular instance with the type's name like `LbrPrelude.Integer`. Note that the `LbrPrelude.Maybe` instance requires knowledge of the `Eq` instance of the `LbrPrelude.Integer`, so we must pass that in as a function argument.
229+
230+
## Type classes in detail
231+
232+
A type class in Typescript is an object type which defines a set of methods.
216233
For example, the `Eq` type class in Haskell defines the set of methods `==` (equality) and `/=` (inequality) as follows.
217234

218235
```haskell
@@ -221,7 +238,7 @@ class Eq a where
221238
(/=) :: a -> a -> Bool
222239
```
223240

224-
The corresponding [`Eq` class](https://github.com/mlabs-haskell/prelude-typescript/blob/main/src/Lib/Eq.ts) in TypeScript is:
241+
The corresponding [`Eq` class](https://github.com/mlabs-haskell/prelude-typescript/blob/main/src/Lib/Eq.ts) in Typescript is:
225242

226243
```ts
227244
export interface Eq<A> {
@@ -230,7 +247,7 @@ export interface Eq<A> {
230247
}
231248
```
232249

233-
Each type class in TypeScript must have an associated global variable which maps unique representations of its instance types to the corresponding object of the type class implementation.
250+
Each type class in Typescript must have an associated global variable which maps unique representations of its instance types to the corresponding object of the type class implementation.
234251
For example, the `Eq` type class has the [global variable](https://github.com/mlabs-haskell/lambda-buffers/blob/main/runtimes/typescript/lbr-prelude/src/LambdaBuffers/Eq.ts#L11) defined in the [lbr-prelude](https://github.com/mlabs-haskell/lambda-buffers/tree/main/runtimes/typescript/lbr-prelude) library defined as follows
235252

236253
```ts
@@ -276,7 +293,7 @@ instance (Eq a, Eq b) => Eq (MyPair a b) where
276293
MyPair a1 a2 != MyPair b1 b2 = a1 != b1 || a2 != b2
277294
```
278295

279-
The corresponding TypeScript type definition and instance would be defined as follows
296+
The corresponding Typescript type definition and instance would be defined as follows
280297

281298
```ts
282299
export type MyPair<a, b> = [a, b]
@@ -297,7 +314,7 @@ This loosely follows the original translation given in the paper [How to make ad
297314

298315
## Limitations
299316

300-
- Only Haskell 2010 typeclasses are supported for the TypeScript code generator. So, the following schemas will probably generate incorrect code.
317+
- Only Haskell 2010 typeclasses are supported for the Typescript code generator. So, the following schemas will probably generate incorrect code.
301318

302319
```purescript
303320
derive Eq (MyPair a a)

0 commit comments

Comments
 (0)