typr 0.3.15

A superset of the legendary R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
# Typr

- [What is TypR?](#what-is-typr)
- [Installation](#installation)
- [For R](#for-r)
- [For Typescript/Javascript/Wasm](#for-typescriptjavascriptwasm)
- [Usage](#usage)
- [Basic documentation](#basic-documentation)
- [Roadmap](#roadmap)
- [Support this project](#support-this-project)

## What is TypR?

It's not only R with types. It's a faster, safer, cooler R that can transpile to `R` and also `Typescript`/`Javascript`/`WebAssembly`.

TypR is a safer counterpart of the legendary R with a transpiler written in Rust. It add cool types, a beautiful syntax and powerful modern features.

The goal is to bring R package developers and developers from differents languages to work in a better way in package management.

The project is still new and have bugs (that will be fixed soon). All the syntax basis and the features are arleady there so there won't be some big breaking change but a refinement of the core elements (and bug fix).

![](images/TypR_logo.png)

## Vapour

There is also a more mature project named vapour written in go who has great features: https://vapour.run/

## Installation

## For RStudio

You can check the [typr.runner](https://github.com/fabriceHategekimana/typr_runner) package to install it directly on RStudio.

## For Scratch
To install TypR, you will need to install `Rust` (of course you should have R installed in your system):

- R's installation page: https://www.r-project.org/
- Rust's installation page: https://www.rust-lang.org/
- Node's installation page: https://nodejs.org/en 

### Installation

After that, you just need to install the cli `typr` (the transpiler) with `cargo` (installed with Rust):

```bash
cargo install typr
```

And you're good to go.

## Usage

Actually, the executable of TypR can:
- Type check the code
- Generate the target code (mainly R actually)
- Create project folders 

You can sse all the faculties of the CLI with the help option:

```bash
typr --help
```

The prefered file extension is `.ty`. It has not it's own syntax highliter yet but I recommend you to use the one from Scala. For instance, if you want to execute a file named `app.ty`, you just need this command:

```bash
typr app.ty
```

## Basic documentation

- Dedicated playlist on youtube French (subtitles in English) but full English version is comming soon): https://www.youtube.com/watch?v=ASPhszv88CM&list=PLSYhtt87oGAJH8Pe-VMcoBkQfek7VJ0hM 


### Philosophy: flexibillity and type safety

#### What is TypR 

"TypR" is a word game with Typescript (a superset of JavaScript) and the common way of naming things in the R community. The initial goal is to create a better experience with building Packages for R (I want them to be easily compatible with the CRAN's requirements and to be easy to ship). Indeed, TypR *is not only a type checker* but bring greater tools to build packages for data science in general and want to be an easy way to convert research paper into code. TypR add great static types and a flexible syntax with some cool tricks (metaprogramming) that make it great to work with.

#### What TypR is not

Although TypR looks like the next cool kid in the town with a syntax greatly inspired by R, Rust and has many interesting feature from Go, Nim and Roc, it doesn't try to replace them at all but tend to help package builder and manager to reach their goals. This will help many developper, to bring value into the R community and the datascience community in a broader scope. 

Even though it follow its principles, TypR is not fundamentally OOP. As well as R who is more of a functional programming language, TypR follow this path for good reasons. Firstly because the realm of datascience is flooded with programming languages who are more on the Object oriented programming side. Don't get me wrong, it has its own strength but its own weaknesses too. Especially because it has his own limits in element representation (uniquely done with OOP) and strange design patterns that could be made easier with functional programming. Functional programming offer a bit more high level representation with less headache and the power of creating easy pipelines and parallelizable code.

### Transpilation process

To explain TypR in an other way, it's a core calculus with quite a bit of syntax sugar.

![](images/transpiler_3_lang.png)

To build the corresponding code for each target language, TypR use a context based on the parsing of the syntax and the type checking of it's construct to build enough knowledge to make inference and simplify the work of developpers. For R, it use the S3 object oriented system underneath. For Typescript/Javascript and Assemblyscript/Wasm it use monomorphization. TypR needs to transpile to Typescript before creating an equivalent javascript file. It also needs to transpile to Assemblyscript before creating wasm files.

### First code

Let's build our first exemple! You can create a file named `app.ty` (or the name you want). TypR has a generalized syntax for building type. To create a numeric, you just have to write:

```scala
let a: num <- 5.0;

a
```

You can now run it with this command:

```bash
typr app.ty
```

You will get this result:

```
Type checking: 
num

Execution: 
[1] 5
# [some other types]
```

As you can see, typR display two things. The first is the result of the type checking. TypR know that you defined a numeric so the expression `a` evaluate to the type `num` (=numeric).

The second thing displayed is the evaluation of the value of the variable `a`. Since we created it with the value `5` it take it as it is.

The `typr` binary created two files to do this task. They exist in the current directory and are respectively named `std.R` and `app.R`. `std.ty` is the file containing a set of predefined variables and types that will be present in each project. There are some default R functions and predefined TypR functions. The `app.R` is the main file with the type annotation removed:

```R
# [other prebuild stuffs to work with typR]
# ...

n <- 5
n
```

You don't need to pay attention to the first lines of the document but to the last two lines. As you see, it's almost the same thing as the `app.ty` document with the exception of some element removed (the "let", and the type annotation). Of course TypR is not just R with types but it brings other great constructs from metaprogramming that will also bring a simpler syntax in TypR. It will build some code for you on the R's side. You can play with it and see it for yourself.

### Types

Even though TypR try to be the closest possible to the type system of R, it also takes its own route for certain things and do the translation of R. For now, not all basic R data types are represented but TypR has its own representation.

*Basic types:*

Each basic type gives a vector of size 1 in R. Boleans are now the two lower-case values `true` and `false` instead of the uppercase one (TRUE, FALSE or T, F).

| name       | TypR  | R       |
|------------|-------|---------|
| Integers   | int   | integer |
| Numerics   | num   | numeric |
| Characters | char  | bool    |
| Booleans   | bool  | logical |

```scala
let a: int <- 5;
let b: num <- 5.0; 
let c: char <- "5";
let d: bool <- true;

a
```

Structural types:

| name                  | TypR                       | R               |
|-----------------------|----------------------------|-----------------|
| Arrays                | ([[index], [type]])        | vector + arrays |
| Records               | ({[[name]: [type]]*})      | lists           |
| Tuples (like records) | ([type]*)                  | lists           |
| Functions             | (([type]*) -> type)        | functions       |
| Tags                  | .[name]\(type)             | NA, NaN, lists? |
| Unions (of Tags)      | type [\| type]+            | -               |
| Interfaces            | interface {a bit too much} | -               |

#### Arrays

One can build an array from any types. Array keep the informations about the array size and it's type. As any other types, you don't need mention the type annotation. TypR can infer it for you.

*Difference with R*
Like R, TypR's array can only hold one type but this type can't change through time. It mean, all the member of the array must have the same type.

*Exemples*

```scala
let a: [3, bool] <- [true, false, true];
let b <- [true, false, true];

a
```

Here `a` and `b` have both the type `[3, bool]` with and without the type inference. 

We can also define multidimensional arrays in that way:

```scala
[[1, 2], [3, 4]]
```

This code will give you this result:

```
Type checking: 
[2, [2, int]]

Execution: 
     [,1] [,2]
[1,]    1    3
[2,]    2    4
```

The array type from TypR are recursive by definition. This mean an array `[I, T]` is the combination of an index `I` and a type `T`, so `T` can be any type including an other array type `[J, T]` so we can end with an array `[I, [J, T]]`. Since R doesn't support this feature, TypR is smart enougth to transform it to a classical Array type in R.

You can also add as much layer as you want (but not realy sure if it's that readable). You can create a tensor of dimension 3 (an array of arrays of arrays) in this fashion:

```scala
[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
```

I will let you see the result by yourself. But be sure to respect the dimensionality or else it will not work.

*Sequences*

Like R, TypR let you define sequence of elements. For instance:

```scala
1:4
```

Will give you this result:

```
Type checking: 
[4, int]

Execution: 
[1] 1 2 3 4
```

TypR also add the feature of defining steps:

```scala
0:2:20
```

Just mean "start from zero by step of two until we reach 20". It will give this result:

```
Type checking: 
[11, int]

Execution: 
[1]  0  2  4  6  8 10 12 14 16 18 20
```

TypR offer capabilities to act on array indexing and build functions that define the shape an array should have. It's a powerful tool let typR infer and check the shape of a multidimensional array like a matrix. For instance, sequences generated are juste converted to the `seq` function in R. TypR has this definition for it:

```scala
pub let seq <- fn(a: #I, b: #J, c: #K): [#J-#I/#K+1, int] {
	...
};
```

At this stage, you dont need to understand everything. This is just a function that take 3 parameters (#I for the start number, #J for the end number and #K for the step) The resulting index is a calculation (#J-#I/#K+1) that TypR can use to guess the shape of the resulting array. This type of generics are `index generics`, those are like super ints who have the power to be used in arrays' index. It give the power to define the resulting shape of complex operations like transpose or the dot product. A tutorial about this topic will come soon (since it can be a whole chapter by imself).

#### Records

A record is a structure that hold different type of data. It's the equivalent of a named list in R. It has also his owns capability like the row polymorphism.

*Difference with R*  
TypR records are a subtype of R lists. You can't build a records with unlabeled values like in R. This restriction prevent unsafe and unpredictible operations to occure.

*Exemples*
To build a simple record representing a person with their name and age, you can just write:

```scala
:{name: "John", age: 19}
```

Will generate:

```
Type checking: 
{name: char, age: int}

Execution: 
$name
[1] "John"

$age
[1] 19
```

To make a distinction with a scope and avoid long names like "list" or "record" for each object creation, We thought this notation will be easier to work with.

To access a member by it's label, you just have to call it in this fashion:

```scala
let person <- :{name: "John", age: 19};

person.name
```

Here, we accessed the name of the person. Records are mainly there to keep together a set of data in a logical way

#### Tuples

R tuples are a specific case of records. Indeed, they are just records who automaticaly generate numered labels. Here:

```scala
:{"John", 19}
```

Will generate:

```
Type checking: 
{char, int}

Execution: 
[[1]]
[1] "John"

[[2]]
[1] 19
```

It's a faster and easier way to generate data on the fly.

#### Functions

Since TypR is more oriented toward a functional style, functions are values and have a type by themself. They are then anonymous by default and should be set in variables.

*Difference with R*
There aren't that much difference with R except function are created with the `fn` keyword instead of the `function` one. Also `return` is not a function anymore but a keyword.

You can define a function with a type annotation but it's better to focus only on the function signature and let TypR infer the rest.

```scala
let f <- fn(a: int, b: int): bool {
	a == b
};

f(8, 9) # will give false
```

TypR functions are the most complex elements of TypR since many action (metaprogramming + type checking) must be done in the calling. But a lot of sugar has been added so everyone can use them seemlessely.

#### Tags

Tags are one of the algebraic data type (no need to know what an algebraic data type is yet) I needed the most but didn't know. I was asking myself wich kind of union type of union I should use (general union or tagged union), but those are the elements that bring at the same type the security and flexibility wanted for this language.


*Difference with R*

R don't have such a construct since, Tags, unions and even interface are an abstract concept to put some clarity and restriction to what the code should do. But compared to the others, tags are a kind of values and should exist in real R code. I have not made the implementation of the translation to R yet, but I think I will make

Tags are values that one can use on the fly. Each flag is unique and has its own type. It's useful do define some elements like:

```scala
let none: .None <- None;
let nan: .NaN <- NaN;
let na: .NA <- NA;

none
```

If the tag is named `[tag_name]`, then it's base type is `:[tag_name]`. They are R's factors on steroïd and even Rust's enums on steroïd. You can use them to define some collections (like the Day of the week, gender, etc.).

Tags can also handle one type with them:

```scala
let results: .Val(num) <- Val(7.3);
let person: .Person({name: char, age: int}) <- Person(:{name: "Marc", age: 37});

results
```

Okay but what are their power ? Well they can be unified together inside a union type ! But here we will see how useful it is for return type in a if close:

```scala
if (true) {
	7
} else {
	"seven"
}
```

Here, TypR wont accept this code since `7` (`int`) and `"seven"` (`char`) aren't the same type. But if we use tags:

```scala
if (true) {
	Value(7)
} else {
	String("seven")
}
```

The return type will be `.Value(int) | .String(char)` meaning TypR will automaticaly unify the results if they are tags. Tags must be "unwrapped" to access the values within, forcing a user to handle the different cases.

#### Union

Union are an abstract concept that won't really appear in the resulting R code. In summary, you can only unify tags. You can now regroup tags to create other type. For instance, to create an option type, one can create an alias into this union of values:


*Difference with R*
There is no concept of union in R so nothing to compare.

```R
type Option<T> = .Some(T) | .None;
```

And if my function can return a `Na` and a `NaN` instead of an int value you can define your own type:

```R
type Failable<T> = .Value(T) | .NaN | .Na | .None;
```

This method is more flexible than an enum like Rust and more secure than an union from TypeScript.

#### Interfaces [still buggy]

TypR interfaces works like Go's interfaces. It's a typed way of doing duck typing: If it walks like a duck and quacks like a duck, then it's a duck. So there is no implicit implémentation of an existing interface.

*Difference with R*
There is no concept of union in R so nothing to compare.

You can define an interface in this fashion:

```scala
type Addable = interface {
	add: fn(a: Self, b: Self): Self,
};
```

You can then define a function that take any addable type in this way:

```scala
let time3 <- fn(n: Addable) {
	add(n, (add(n, n))
};
```

The type int already had the function add that respect the interface `Addable`, so it will be immediatly accepter to pass an int in this fuction in different ways:

```scala
time3(5)
(5).time3()
5 |> time3()
```

### Main functionalities

- Uniform function call
- Operator overloading
- Generics + Index Generics
- Type embedding
- Interface inference
- Row polymorphism

#### Uniform function call

UFC (uniform function call) is one of my favourite features in programming language. I love the simplicity of methods, but I am not a fan of classes anymore since they are less expressive than algebraic data types in general. But working with my functions using types and module and pipes isn't totaly complet without methods call. So UFC bring the best of both worlds to me. I have also added some other forms with the original.

For instance, we can see the definition of the add function for interger types:

```scala
let incr <- fn(a: int): int {
	a + 1
};
```

Now we can call it in different ways that gives the same results:

```scala
incr(2)
(2).incr()
2 |> incr()
```

There are the special elements `..` or `|>>` that make a function operate on an array level.

```scala
[1, 2, 3]..incr()
[1, 2, 3] |>> incr()
```

This code will apply an addition with 3 for each element.

#### Operator overloading

Operator overloading is one of my favourite element to build operations on types. It's a shortcut and a syntax sugar that let the user define operations for their custom types.

Imagine we create a type named point:

```scala
type Point = {x: int, y: int};

let p1 <- :{x: 2, y: 1};

p1
```

You can define a function `add` to add two points. Let's assume you just add each coordinates.

```scala
let add <- fn(p: Point, q: Point): Point {
	:{x: ((p.x) + (q.x)), y: ((p.y) + (q.y))}
};
```

You can obviously use the function in differtent ways:

```scala
add(p1, p1)
p1.add(p1)
p1 |> add(p1)
```

But you can also add point in this fashion:

```scala
p1 + p1
```

Why is it possible ? Because `add` is a reserved symbol related to the binary operation `+`. So each time TypR see a `a+b`, it transform it to `add(a, b)`.

There are a group of reserved operators that change to their function's form.

| operator | function name |
|----------|---------------|
| +        | add           |
| ++       | add2          |
| -        | minus         |
| --       | minus2        |
| *        | mul           |
| **       | mul2          |
| /        | div           |
| //       | div2          |
| @        | at            |
| @@       | at2           |

You don't have to worry about the usage of if an operator is related to an other type. Each type can use each symbol once.

#### Modules

Modules are a useful tool that allow us to use the same name but in a different scope.

```scala
module Foo {
	pub let my_var <- "hey";
};

module Bar {
	pub let my_var <- true;
};

let my_var <- 7;

Foo::my_var
Bar::my_var
my_var
```

In this exemple, my_var is defined in 3 different place with a different value and even a different type each time. But if `my_var` is defined in a module like in the `Foo` or `Bar` module then we need to prefix the module name to have access to this variable.

In OOP language we think in term of class and object, in language with a functional programming paradim orientation like TypR, we think in term of types. A type can be refered at any moment in the program and function that works with this type can also be declared at any moment in the program. This is why module exists: if needed, we can group types and their related functions in the same place and give it a name for reference.

```scala
# not working yet
module Cat {
	pub type Cat = {name: char, age: int};
	
	pub let cry <- fn(c: Cat): char {
		"meow"
	};
};

let felix <- :{name: "Felix", age: 8};
Cat::cry(felix)
```

#### Generics + Index Generics

Generics is one of the hardest concept in this language, especially when we talk about Index Generics.

In complex terms, generics is a way to create functions that allows functions to work with more types related to specific relationship with parameters (Parametric polymorphism).

Since it allow almost any type, it's better to use them for structural and general purpose. For instance, it's great to describe data structures that can works with many types (like array, graphs, tree, etc.). It's also greate to use it to shape function composition.

## Roadmap

This project needs more refinement and the documentation will evolve throug it's iterations. Mainly, I am trying to reach thos goals:

- Update the documentation
- Dedicated WebSite
- Finish the type embedding's implementation
- Better interface inference
- Label Generics
- Vectorial blocs
- Finish Typescript/Javascript implementation
- JS blocs
- Finish WASM implementation

## Support this project

If you find this project useful or interesting, there are several ways you can support it:

- **Contribute** by improving the code, reporting issues, or suggesting features  
- **Donate** via [Patreon](https://patreon.com/FabriceHategekimana?utm_medium=unknown&utm_source=join_link&utm_campaign=creatorshare_creator&utm_content=copyLink) to help sustain development  
- **Share** the project with others who might benefit from it

Every contribution, no matter how small, helps this project grow. Thank you!