# Annot+ : an annotation and inference type system for Scheme

**URL:** <https://racket.discourse.group/t/annot-an-annotation-and-inference-type-system-for-scheme/4464>\
**Category:** Show & Tell\
**Created:** [November 8, 2026, 1:06am UTC](https://racket.discourse.group/t/annot-an-annotation-and-inference-type-system-for-scheme/4464 "2026-11-08T01:06:56Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![damien\_mattei](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/damien_mattei/32/2706_2.png) [@damien\_mattei](https://racket.discourse.group/u/damien_mattei)\
**Post date:** [November 8, 2026, 1:06am UTC](https://racket.discourse.group/t/annot-an-annotation-and-inference-type-system-for-scheme/4464/1 "2026-11-08T01:06:56Z")

</div>

Bonjour,

i present **Annot+** an annotation and inference type system for scheme/racket/scheme+

 ![image](https://global.discourse-cdn.com/free1/uploads/racket/original/2X/3/3dc7a2bba1afef6d8a997bb1ae4171f61be9c78d.jpeg)

[CC BY-SA 3.0](http://creativecommons.org/licenses/by-sa/3.0/)

I used a one pass method parsing the AST (abstract syntax tree) of a scheme program (racket module) taking apart annotation types declaration and using them to rewrite code and doing this recursively.  
Naive idea ! things being very more complex in reality. You have to be very careful with the core of the algorithm.I did not used known theory (like Hindley Milner). I used my own method instead.

[Annot+](https://github.com/damien-mattei/SRFI-105-for-Racket/blob/main/bootstrapping/annot%2B.rkt) is written itself in [curly-infix/scheme+](https://github.com/damien-mattei/Scheme-PLUS-for-Racket) using [bootstrapping](https://en.wikipedia.org/wiki/Bootstrapping_(compilers)) method.

![lisplogo_warning_128](https://global.discourse-cdn.com/free1/uploads/racket/original/2X/8/8a0f5ca78ffec31175bd87e2af400935db028d44.png) Public Domain Lisp Logo Set By Conrad Barski, M.D.

Here is the scheme+ source code of annot+.rkt :

> <https://github.com/damien-mattei/SRFI-105-for-Racket/blob/main/bootstrapping/annot%2B.rkt>

**Annot+** can speed up **arithmetic operations** in scheme,also with **overloaded procedures or operators** ,then as fast as if it was pure scheme code and does the same for **`[]` indexed access** in scheme+.

**Annot+ dispatch overloaded procedure with their specialized one depending on argument type at parsing stage** : the consequence is there is no more lost of time at runtime.

Here is a little example using the `type` annotation:

```scheme
(type [(ℝ) procedure? ()] random) ; random is a procedure returning a racket/flonum? = ℝ

; return a random number between [inf, sup]
(define (uniform-interval inf sup)
  
  (type ℝ inf sup) ; inf and sup are some ℝ
  
  {gap ← sup - inf}
  {inf + gap * (random)})

```

the above annotated scheme+ code is parsed and the resulting scheme code is :

```scheme
(define (uniform-interval inf sup)
    (← gap (fl- sup inf))
    (fl+ inf (fl* gap (random))))

```

The benchmarks talk by themselves:

| program (same source) | Scheme | Scheme+ | Scheme+ annotated | Typed Racket | gain |
| --- | --- | --- | --- | --- | --- |
| floats: Horner, sigmoid, 2·10⁷ | 753 ms | 777 ms | 223 ms | 226 ms | 3.4 × |
| matrices 200×200, 20 products | 1065 ms | 1066 ms | 606 ms | 578 ms | 1.8 × |
| integers: Syracuse up to 10⁶ | 986 ms | 985 ms | 382 ms | 402 / 1099 ms | 2.6 × |
| trapezoids, 2·10⁷ steps | 359 ms | 349 ms | 68 ms | 69 ms | 5.3 × |

Type annotation is an option you can type only a portion of code when you need speed acceleration, you do not need to make a type annotation for all your variables or for all the code. (even in an ANNOTATION-ON module)

Another more complex example about a neural network retropropagation loop:

```scheme
#reader SRFI-110 ; 105 ; curly-infix 
#!curly-infix

ANNOTATION-ON

(require Scheme)

(struct matrix-vect (v)) ;; matrix based on vector of vectors
; modify coefficients layer

;; define getter,setter
(define (matrix-vect-ref M lin col)
  (type vector? v {v[]}) ; a vector of vectors : v[lin][col] is specialized for vectors
  (type ℕ lin col)
  {v <- (matrix-vect-v M)}
  {v[lin][col]})

(define (matrix-vect-set! M lin col x)
  (type vector? v {v[]}) ; a vector of vectors : v[lin][col] is specialized for vectors
  (type ℕ lin col)
  {v <- (matrix-vect-v M)}
  {v[lin][col] <- x})

;; overload [] 
(overload-square-brackets matrix-vect-ref matrix-vect-set! (matrix-vect? number? number?))

(define (modification_des_poids M_i_o η z_input z_output z̃_output ᐁ_i_o მzⳆმz̃) ; derivative of activation function of the layer

	  (type matrix-vect? M_i_o) ; M_i_o[j (i + 1)] calls matrix-vect-ref / matrix-vect-set! directly
	  ; M_i_o[j k] is a flonum by the return type in require-overload-square-brackets
	  (type ℝ η)
	  (type #(ℝ) ᐁ_i_o z_input z_output z̃_output)
	  (type ((ℝ) procedure? (ℝ ℝ)) მzⳆმz̃) ; the parameter მzⳆმz̃ hides the one of the class : its type is written here
	 
	  ; the length of output and input layer with coeff. used for bias update
	  {(len_layer_output len_layer_input_plus1forBias) <+ (dim-matrix-vect M_i_o)} ; use values and define-values to create bindings
        
	  {len_layer_input <- len_layer_input_plus1forBias - 1}

	  (type ℕ j)
	  (for ([j (range len_layer_output)]) ; line

		(type ℕ i)
		(for ([i (range len_layer_input)]) ; column , parcours les colonnes de la ligne sauf le bias
		   
		    {M_i_o[j (i + 1)] <- M_i_o[j (i + 1)] + η · z_input[i] · მzⳆმz̃(z_output[j] z̃_output[j]) · ᐁ_i_o[j]})
		   
		; and update the bias
            	
		{M_i_o[j 0] <- M_i_o[j 0] + η * 1.0 * მzⳆმz̃(z_output[j] z̃_output[j]) * ᐁ_i_o[j]}))
	

```

notes about the above example: it is not n but η (but η displays as n in code region over discourse)

the example is extracted from module files so do not expect it to work as is : what really works ! are the complete files in examples subdirectories of project.

 ![neural-harmonic-oscillator-and-equation-computed-harmonic-oscillator](https://global.discourse-cdn.com/free1/uploads/racket/original/2X/e/e95f932506aef7ec50bcf159471ffee6e54f02a0.png)

On the above example of neural retropropagation activating (pragma ANNOTATION-ON) or disabling the annotation (pragma ANNOTATION-OFF) pass changes the speed in a factor of x7 : with type annotation and inference the program is **7 times faster**.

Last note:

type annotation works also with nested composite types: the composite types `#(T)` (a vector) and `(T)` (a list) compose at any depth: the type of the elements T can itself be a composite type. Some examples of nested composite annotations:

```scheme

(type #(#(ℝ)) M) ; vector of vectors of floats (a matrix)
(type #(#(#(ℝ))) T) ; vector of vectors of vectors of floats (a 3D array)
(type #(#(ℕ)) grid) ; vector of vectors of natural fixnums
(type (#(ℤ)) Lv) ; list of vectors of fixnums
(type #((ℝ)) VL) ; vector of lists of floats
(type ((ℝ)) LL) ; list of lists of floats
(type ((#(ℝ))) LLv) ; list of lists of vectors of floats
(type #(#()) V2) ; vector of vectors with untyped elements
(type #(flomat?) Ms) ; vector of flomat matrices
(type (#(string?)) Ls) ; list of vectors of strings

```

The documentation and packages can be find here:

> **[Scheme+ for Racket](https://docs.racket-lang.org/Scheme-PLUS-for-Racket/index.html)**

Why **annot** name? because it is **annot** ation and also for a mountain village near me :

 ![image](https://global.discourse-cdn.com/free1/uploads/racket/original/2X/d/d2341ea64e6f0ba1f9c96db9e54aad31eb20e853.jpeg)

[CC BY-SA 3.0](http://creativecommons.org/licenses/by-sa/3.0/)

> **[Annot](https://en.wikipedia.org/wiki/Annot)**
>
> Annot (.mw-parser-output .IPA-label-small{font-size:85%}.mw-parser-output .references .IPA-label-small,.mw-parser-output .infobox .IPA-label-small,.mw-parser-output .navbox .IPA-label-small{font-size:100%}French pronunciation: \[anɔt\]; Occitan: Anòt) is a commune in the Alpes-de-Haute-Provence department in the Provence-Alpes-Côte d'Azur region of southeastern France. The commune has been awarded one flower by the National Council of Towns and Villages in Bloom in the Competition of cities and v...

update: source file
