Scheme+   for Racket
1 Both prefix and infix expressions in the same world
2 Scheme+   Installation and Depandencies
3 Scheme+   and Curly Infix SRFI-105 REPL (Read Eval Print Loop)
4 A simple Hello World application in Scheme+   and Curly Infix
5 Scheme+   Syntax and Conventions
5.1 Curly Infix notation with { }
5.2 Square Bracket notation with [ ]
:
5.3 File naming conventions
6 Scheme+   Reference
6.1 Declarations
declare
6.2 Definitions
6.3 Assignments
6.4 Procedure definitions
def
return
return-rec
def+
6.5 Control flow :   Conditionals and Loops
if
when
unless
condx
repeat
while
for
in-range
reversed
6.6 Blocks
$>
$+  >
6.7 Operators and Procedures
@
**
<<
>>
&
&&
∣∣
·
6.8 Superscript
6.9 Overloading procedures and operators
define-overload-procedure
overload-procedure
define-overload-existing-procedure
overload-existing-procedure
define-overload-operator
overload-operator
define-overload-existing-operator
overload-existing-operator
define-overload-n-arity-operator
overload-n-arity-operator
define-overload-existing-n-arity-operator
overload-existing-n-arity-operator
overload-square-brackets
7 Using Makefile and debugging Scheme+   program
8 Place to find Scheme+   programs and examples
9 Emacs configuration for syntax highligting of Scheme+
10 Thoughts
8.18

Scheme+ for Racket🔗ℹ

 #reader SRFI-105 package: SRFI-105-for-Racket
This reader package provides the SRFI-105 Curly Infix reader/parser.

This package provides the Scheme+ language definitions.

Scheme+ is an extension of the syntax of the Scheme language.

Scheme+ adds to Scheme a way to use also infix notation with a compatibility near 100% and not as a sub-system of Lisp syntax as it is often done but with a complete integration in the Scheme reader/parser system and also for Racket at REPL (Read Eval Print Loop).

Scheme+ is to Scheme what a concept-car is to automobile.Scheme+ is a concept-language.It is ideally what should be a modern Scheme. As Scheme+ syntax is compatible with Scheme syntax you can mix the two syntaxes in the same program.

Scheme+ makes it easy the assignment of Scheme objects in infix (works also in prefix) notation with a few new operators <- (or: ← , :=),⥆ (or <+) for definitions.

Scheme+ makes it easy the access and assignment for arrays,strings,hash tables,etc by allowing the classic square brackets [ ] of other languages.

What Scheme+ is not: Scheme+ is not a DSL (Domain Specific Language) a contrario Scheme+ tends to be the more universal possible and to be applied in a lot of domains.

    1 Both prefix and infix expressions in the same world

    2 Scheme+ Installation and Depandencies

    3 Scheme+ and Curly Infix SRFI-105 REPL (Read Eval Print Loop)

    4 A simple Hello World application in Scheme+ and Curly Infix

    5 Scheme+ Syntax and Conventions

      5.1 Curly Infix notation with { }

      5.2 Square Bracket notation with [ ]

      5.3 File naming conventions

    6 Scheme+ Reference

      6.1 Declarations

      6.2 Definitions

      6.3 Assignments

      6.4 Procedure definitions

      6.5 Control flow : Conditionals and Loops

      6.6 Blocks

      6.7 Operators and Procedures

      6.8 Superscript

      6.9 Overloading procedures and operators

    7 Using Makefile and debugging Scheme+ program

    8 Place to find Scheme+ programs and examples

    9 Emacs configuration for syntax highligting of Scheme+

    10 Thoughts

1 Both prefix and infix expressions in the same world🔗ℹ

You can mix infix sub-expressions and prefix sub-expressions in the same expression:
{(3 + 1) * (2 * (+ 2 1) - (sin 0.3)) + ((* 2 5) - 5)}
27.817919173354642

The above expression is automatically parsed and converted in a classic scheme prefix expression before evaluation:
(+
 (*
   (+ 3 1)
   (- (* 2 (+ 2 1)) (sin 0.3)))
  (- (* 2 5) 5))

Other examples:

(define (fib n)
  (if {n < 2}
      n
      {(fib (n - 1)) + (fib (n - 2))} ))
 
(fib 7)
13
{(- 7 (3 * (+ 2 4) - 1)) + 3}
-7

The parsing is the result of sometimes up to 3 stages of parsing:
  1. SRFI 105 Curly Infix is an external parser necessary for the curly brackets { } syntax which is not in the base of scheme language.

  2. Syntax transformers are sometimes used at a "compile" stage before the code run.

  3. Parsing at runtime is rarely done but can be necessary when the parsed expression or some of her subexpressions remain ambiguous at prior parsing stages about being infix or prefix expressions.

Here the parsing process is activated by the encountering of curly parenthesis { } in the expressions (there exist also other ways to force the parsing):

(define (line-length x0 y0 x1 y1)
  ( {(x1 - x0) ² + (y1 - y0) ²}))
 
{(ksy / ( 2)) * ((- x) + y)}
 
(define (norm x y)
  {x ² + y ²})

2 Scheme+ Installation and Depandencies🔗ℹ

Scheme+ can be installed via the Racket Package system or downloaded from Github.See the links at the top of this page. Scheme+ is designed to be used with the package SRFI-105 for Racket which is a curly infix reader also available in the same way described above.

3 Scheme+ and Curly Infix SRFI-105 REPL (Read Eval Print Loop)🔗ℹ

As Scheme+ is designed to be used with the Curly infix syntax of SRFI-105, the latter one requires an external reader/parser and a specific REPL (Read Eval Print Loop). The REPL must be loaded in Racket GUI or invoked in the shell if you work in command line mode. The REPL file can be found in the source code of Scheme+ or SRFI-105 in the src/ sub-directory, his name is REPL-Scheme-PLUS.rkt.

Here is the source code of REPL-Scheme-PLUS.rkt which is also a typical example of how to write a simple Scheme+ module or program:
#! /usr/bin/env -S racket --load REPL-Scheme-PLUS.rkt --repl
;; the line above is not mandatory,only for launching a script in command line
;; in CLI you must (require Scheme+) manually
;; but if you want to have syntax color in CLI start racket yourself and do:
;; (load "REPL-Scheme-PLUS.rkt")
 
#lang reader SRFI-105 ; SRFI-105 Curly-infix-expressions
 
(module repl racket
 
  (provide (all-defined-out))
  (require Scheme+)
 
  ;; put your code here or simply use the REPL
 
  )

4 A simple Hello World application in Scheme+ and Curly Infix🔗ℹ

#lang reader SRFI-105 ; SRFI-105 Curly-infix-expressions
 
(module hello-world racket
 
  (provide (all-defined-out))
  (require Scheme+)
 
  (display "Hello world") (newline)
 
  )

note it seems in the latest version of Racket we can replace the first line simply by :
#reader SRFI-105 (provide (all-defined-out)) (require Scheme+) (display "Hello world") (newline)

5 Scheme+ Syntax and Conventions🔗ℹ

5.1 Curly Infix notation with { }🔗ℹ

In general Scheme+ use the same convention for infix expression than SRFI-105 Curly Infix that is an infix expression is between curly parenthesis { }. But infix sub-expressions are allowed to be between normal parenthesis ( ) like it is in mathematic notation. Infix or prefix is then autodetected.In case of ambiguities { } force infix mode. Inside curly infix expression surrounded by { } parenthesis associativity and operator precedence are applied.

#reader SRFI-105 (require Scheme+) > {3 * 5 + 2} ; the displayed symbol > is here only the Racket prompt (+ (* 3 5) 2) ; generated code displayed by REPL/parser 17 ; result
{3 * 7 + 2 - 12 / 3 + -2}
17

In the examples the display of the REPL/parser in prefix will generally be removed from examples for clarity, also the prompt > and the displayed #<eof> (end of file) printed by the SRFI-105 parser.

#lang reader SRFI-105
(require Scheme+)
{3 · 5 + 2 ³}
23

Note that in the above example and in Scheme+ the operator · is *, also note that superscript chars are exposants.

In the following sections i will omit to rewrite the directives about lang or reader and the requirement in each example to keep the code and the web page compact.

An example of inner round brackets inside curly brackets in a full infix expression:

(define x {3 * (2 + 4) - 1})
(display x)
17

Example of a mixed infix and prefix expression autodetected:

{3 * (+ 2 4) - 1}
17

Other examples:

(define (fib n)
  (if {n < 2}
      n
      {(fib (n - 1)) + (fib (n - 2))} ))
 
(fib 7)
13
{3 ² + 2 · 3 · 5 + 5 ²}
64

5.2 Square Bracket notation with [ ]🔗ℹ

The square bracket notation can be used with any object that can be indexed or retrieved by a key: it works with vectors,strings of characters, arrays, hash tables,etc.

syntax

{T[k]}

Return value of vector or in general object T indexed by k.

{#(1 2 3 4)[2]}
($bracket-apply$ #(1 2 3 4) 2) ; code generated by the parser
3
 

I will not always display generated code by parser and end of file symbol as only the result is important for the programmer.

{#(1 2 3 4)[1]}
2
(define T (vector 1 2 3 4 5))
{T[3]}
4
{"hello"[4]}
#\o

Negative index, that start from the end of object, can be used as in the Python language:
{"hello"[-4]}
#\e

A slice notation with : is available.It allows the same features as the slicing of Python language and sometimes more.

syntax

{T[begin : end]}

Slicing of vectors or strings.

{"elephant"[2 : 5]}
"eph"
{#(1 2 3 4 5)[2 :]}
'#(3 4 5)
{#(1 2 3 4 5 6 7)[2 * 5 - 8 : 3 * 5 - 10]}
'#(3 4 5)
(define a 0)
(define b 5)
{"hello world"[a : b]}
"hello"

syntax

{T[begin : end : step]}

begin, end, step are optional, see the Python language documentation for informations and use.

{#(1 2 3 4 5 6 7 8 9)[3 : 8 : 2]}
'#(4 6 8)
{#(1 2 3 4 5 6 7 8 9)[-1 : 5 : -1]}
'#(9 8 7)
{#(1 2 3 4 5 6 7 8)[: : 3]}
'#(1 4 7)
{#(1 2 3 4 5 6 7 8)[: : -2]}
'#(8 6 4 2)
{"abcdefghijklmno"[3 : : 2]}
"dfhjln"

The square bracket notation [ ] works also with multiple dimensions vectors:

{M <- #(#(1 2 3)
        #(4 5 6))}
{M[1][2]}
6

You can use also this [ ] notation variant, like matrix notation, and compatible with arrays in case of you use them:

{M <- #(#(1 2 3)
        #(4 5 6))}
{M[1 2]}
6

Examples:

{[i][k] <- y[k] - z[i][k]}

5.3 File naming conventions🔗ℹ

Generally a Scheme+ program file is named with a + symbol before the normal scheme extension, examples: SssDyna+.scm or SssDyna+.rkt.The Makefile (see section more below) i provide will automatically parse files named with this convention.

6 Scheme+ Reference🔗ℹ

6.1 Declarations🔗ℹ

syntax

(declare name1 name2 ...)

Declare new variables named name1,name2,....

(declare x)
(when (identifier-binding #'x)
    "variable x exists")
"variable x exists"

You can not both declare and define a variable in a program (module):

#reader SRFI-105 (provide (all-defined-out)) (require Scheme+) (declare x) (define x 3)

module: identifier already defined in: x

Note that declare is rarely used,instead assignment macros like <- are used, but it could be usefull in case a variable used in a block must be used outside the scope of the block too like in this example:

(declare x)
{t <- 3}
(when {t > 1}
  {x <- 7})
{x <- x + 1}
x
 
8 ; result

By default the declared variables are set to NIL, that is ’()

(declare x)
x
'()

6.2 Definitions🔗ℹ

syntax

{name <+ value}

Define new variable name and assign value value. Mnemonic of <+ is to add a new variable in the environment.

{x <+ 7}
x
7

Note: this is almost never used in Racket,because Scheme+ for Racket has a special feature of autodetecting if a variable needs to be defined before assignment and in this case it will define it for the programmer in the current block.

There is some alias of <+ :

syntax

{name  value}

Note: a lot of operators of Scheme+ that works left to right exist in the opposite sense, i will not document them as it is obvious,example:

syntax

{value  name}

Also a lot of Scheme+ operator have infix n-arity capability , i will not completely document them at the beginning of this document but in other parts later.

{name  name2  7}
(list name name2)
'(7 7)

6.3 Assignments🔗ℹ

syntax

{name <- value}

Assign to the variable name the value value.

{x <- 7}
x
7

If the variable was not existing in the current environment it will be automatically declared,this is a special feature of the Scheme+ version for Racket that can rarely be reproduced in other scheme implementations.

There is some alias of <- :

syntax

{name := value}

{index := index + 1}

syntax

{name  value}

{z  1.13+1.765i}

syntax

{(name1 name2 ...) <- values}

You can also use the assignment or definition operators for creating tuples (like in Python) of values.

{(x y z) <- (values 1 2 3)}
(list x y z)
'(1 2 3)

The assignment operator is a macro that works in taking in account the square bracket [ ] notation in the RHS (right hand side) of any expression:

(define T (make-vector 5))
{T[3] <- 7}
{T[3]}
7

Remember :=,for Pascal language fans, is exactly the same as <-.

(require srfi/25)
{a := (make-array (shape 0 5 0 3) 0)}
{a[1 2] := 7}
{a[1 2]}
7

Other example:

{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]}

Note in the example above the special neoteric expression available by SRFI-105 Curly Infix: მzⳆმz̃(z_output[j] z̃_output[j]) which is automatically parsed and transformed in the prefix expression : (მzⳆმz̃ z_output [j] z̃_output [j]), note also that მzⳆმz̃ is only a symbol.

Assignment and slicing works as in Python language or even better,allowing more possibilities.

Examples:

{v <+ (vector 1 2 3 4 5 6 7 8 9)}
'#(1 2 3 4 5 6 7 8 9)
{v[: : 2] <- (vector -1 -2 -3 -4 -5)}
v
'#(-1 2 -2 4 -3 6 -4 8 -5)

Note: remember <+ is for new definitions but in Racket i could have directly use <-.

{v <+ (vector 1 2 3 4 5 6 7 8 9)}
{v[: : -2] := (vector -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13)[: : 2]}
v
'#(-9 2 -7 4 -5 6 -3 8 -1)

Remember := is exactly the same as <-.

{v <+ (vector 1 2 3 4 5 6 7 8 9)}
{v[: : -2] <- "abcdefghijklmnop"[: : 2]}
v
'#(#\i 2 #\g 4 #\e 6 #\c 8 #\a)
{v <+ (vector 1 2 3 4)}
{v[1 : 3] <- "abcdef"[2 : 4]}
v
'#(1 #\c #\d 4)
{v <+ (vector 1 2 3 4 5 6 7 8)}
{v[3 : : 2] := (vector -1 -2 -3)}
v
'#(1 2 3 -1 5 -2 7 -3)
{v <+ (vector 1 2 3 4 5 6 7 8)}
{v[5 : : -2] <- (vector -1 -2 -3)}
v
'#(1 -3 3 -2 5 -1 7 8)
{v <- (vector 1 2 3 4 5 6 7 8 9)}
{v[7 : 2 : -2] <- (vector -1 -2 -3)}
v
'#(1 2 3 -3 5 -2 7 -1 9)

6.4 Procedure definitions🔗ℹ

syntax

(def (name args ...) body ...+)

Define a procedure (also named function). This does the same as the classic define but allows the program to return from the body of definitions at any moment. This works the same as in other languages such as C or Python languages.

syntax

(return value ...)

Return immediately from the executing procedure defined with def and return the values: value ... . As the ellipsis indicate it, you can return multiple values.

Example:

(def (foo L)
   (when (null? L)
      (return "empty list"))
   (cons "hello list :" L))
 
(foo '())
"empty list"

Note: return can only be used inside a def :

(return 7)
return: can only be used inside def and def+

Another example:

;; this procedure check that we have a canonical infix expression
;; i call 'canonical' an expression such as 3 * 5 + 2
;; in contrary an equivalent expression such as this one: - - 3 * 5 + 2 is not 'canonical',etc
;; conditions to be 'canonical' will be to have :
;; * at least 3 terms in expression
;; * odd number of terms
;; * operators between terms
(def (infix-canonical? L)
 
          (define lgt (length L))
          (when (or (< lgt 3)
                    (not (odd? lgt)))
            (return #f))
 
          (def (check-operators? L2)
            (when (null? L2)
              (return #t))
            (if (not (operator-syntax? (car L2)))
                #f
                (check-operators? (cddr L2))))
 
          (check-operators? (cdr L)))
 
(infix-canonical? '(2 * 3 4))
#f
 
(infix-canonical? '(2 * 3 + 4))
#t

syntax

(return-rec value ...)

return-rec will return from all the previous recursive calls of the executing procedure (if it was a recursive function).

syntax

(def name args args-optional ...)

Define name with (args args-optional ...) forming an infix expression.

(def t  3 * (+ 2 4) - 1)
t
17
 
(def z  (3 + 1) * (2 * (+ 2 1) - (sin 0.3)) + ((* 2 5) - 5))
z
27.817919173354642

syntax

(def name)

Like declare.

syntax

(def+ (name args ...) body ...+)

Same as def but all body ... will be analyzed as possibly infix or still prefix.

6.5 Control flow : Conditionals and Loops🔗ℹ

syntax

(if test then then-body ... else else-body ...)

Evalutes test and, if test is True, evaluates then-body ..., otherwise it evaluates else-body .... Note that multiple expressions can be placed in each block in the syntax; you can remove the then or/and else block delimiters as long as there is no ambiguities with the syntax you expressed,so you can fall back to the classic scheme if form and it is backward compatible with the classic scheme syntax.

(if #t then "True")
"True"
(if #f then
      "You"
      "should"
      "not"
      "be"
      "there."
    else
      "I"
      "am"
      "here")
"here"

Example from real code:

(if (singleton-set? sos) then
 
      ;; singleton
      (reverse acc)
 
   else
 
         ;; at least 2 elements in set of sets
         {mt-set1 <- (car sos)} ;; minterm set 1
         {mt-set2 <- (cadr sos)} ;; minterm set 2
         {mt-set2-to-mt-setn <- (cdr sos)} ;; minterm sets 2 to n
         {weight-mt-set1 <- (floor-bin-minterm-weight (car mt-set1))} ;; in a set all minterms have same weight
         {weight-mt-set2 <- (floor-bin-minterm-weight (car mt-set2))}
         {delta-weight <- {weight-mt-set2 - weight-mt-set1}}
 
         (if {delta-weight = 1} then ;; if minterms set are neighbours
 
             ;; unify neighbours minterms sets
             {unified-mt-set1-and-mt-set2 <- (funct-unify-minterms-set-1-unit-threads mt-set1 mt-set2)}
             (if (null? unified-mt-set1-and-mt-set2)
                 (funct-unify-minterms-set-of-sets-rec-tail mt-set2-to-mt-setn acc) ;; the result will be the continuation with sets from 2 to n
                 (funct-unify-minterms-set-of-sets-rec-tail mt-set2-to-mt-setn (insert unified-mt-set1-and-mt-set2 acc)))
 
          else
 
             (funct-unify-minterms-set-of-sets-rec-tail mt-set2-to-mt-setn acc))) ;; continue with sets from 2 to n

syntax

(when test body ...)

syntax

(unless test body ...)

Scheme+ implementation provides both when and unless forms that allow declarations and statements in their body. The when and unless forms already exist in Racket implementation. Refer to the Racket documentation about them.

syntax

(condx (test body ...)
       (exec body ...)
       ...
       (else body ...))
A cond that allow execution of code or even definitions between the test clauses.

(define x 1)
(condx ((= x 7) 'never)
        (exec
          (define y 3)
          (set! x 7))
        ((= y 1) 'definitely_not)
        (exec
          (set! y 10)
          (define z 2))
        ((= x 7) (+ x y z))
        (else 'you_should_not_be_here))
 19

Note that scheme cond and scheme+ condx are a style of programming, you can use other style with same result, i think of using def and return with when and if that can replace them.

Example from real code of the subset sum problem from the file SssRec+.rkt in examples directory :

{c <- (first L)}
{R <- (rest L)}
(condx [ {c = t} (return #t
                         (cons c s)) ] ;; c is the solution
 
       [ {c > t} (ssigma-solution-exact R t s) ] ;; c is to big to be a solution
 
       ;; c < t at this point
       ;; c is part of the solution
       [ exec {(c-sol sol) <- (ssigma-solution-exact R (t - c) s)} ]
 
       [ c-sol (return c-sol
                       (append (cons c s) ; c is in the solution for t, we insert it in the previous partial solution
                               sol)) ] ; we append with sol to get also the solutions of t - c,resulting in solutions of c + (t - c) = t
 
       ;; or c is not part of solution
       ;; or the two ! perheaps there exists 2 solutions using or not using c ! (in this case we got only the first found!)
       [ else
          (ssigma-solution-exact R t s) ] )

Note about the example above which mix condx and return because it is part of a procedure not displayed here, i encourage the reader to see the full source code SssRec+.rkt to understand it better.

syntax

(repeat body ... until test)

Like in Pascal or Lua: loop over body ... until test is true.

{i := 5}
(repeat
     (display i)
     (newline)
     {i := i - 1}
   until {i < 0})
 
5
4
3
2
1
0

Note: above i used := which is exactly the same as <- or .

syntax

(while test  body ...)

Initially the syntax should be as while ... do from Pascal but not possible as do already exist in scheme.

syntax

(for (initialization condition updation) body ...)

Syntax of for ... as it exists in C/C++,Javascript,Java language.

(for ({i := 0} {i < 3} {i := i + 1})
    (display i)
    (newline))
0
1
2

Other examples:
(for ({i <- 0} {i < n - 2} {i <- i + 1})
    ;; create an array with 1 in front for the bias coefficient
    {z_1 <- #(1) + z[i]} ; + operator has been overloaded to append scheme vectors
    {[i + 1] <- M[i] · z_1} ;  = matrix * vector , return a vector
    {z[i + 1] <- vector-map(activation_function_hidden_layer [i + 1])})

Example from matrix multiplication, compute element i,j of result:

(for ({k <- 0} {k < p1} {k <- k + 1})
    {sum <- sum + M1[i][k] * M2[k][j]})

Note about Scheme+ for Racket: the for described above replace the original for of Racket, you should back up it as below before using that. Also Scheme+ define in-range and reversed as in Python language but they already exist in Racket Scheme.

(require (only-in racket/base [for for-racket])) ;; backup original Racket 'for'
(for-racket ([i (reverse (range 1 i_output_layer))])
                                {nc <- vector-length(z[i])}
                                {ns <- vector-length(z[i + 1])}
                                (for-racket ([j (range nc)])
                                        {[i][j] <- (for/sum ([k (range ns)])
                                                             (მzⳆმz̃(z[i + 1][k] [i + 1][k]) · M[i][k (j + 1)] · [i + 1][k]))})
                                ; modification des poids de la matrice de transition de la couche i-1 à i
                                {modification_des_poids(M[i - 1] ηₛ  z[i - 1] z[i] [i] [i] მzⳆმz̃)})

syntax

(in-range start stop step)

As range in Racket or Python

syntax

(reversed in-range-expression)

As reverse in Scheme or reversed in Python

6.6 Blocks🔗ℹ

syntax

($> body ...)

$> is as begin.
(if (compare-minterm-and-implicant {iepi[lin 0]}
                                   {iepi[0 col]})
                ;; then
                ($>
                  (incf cpt-mt)
                  (when (= 1 cpt-mt)
                        {lin-pos-epi  lin}) ;; position of essential prime implicant
                  {iepi[lin col]  1})
 
                ;; else
                {iepi[lin col]  3})

syntax

($+> body ...)

$+> will allow also definitions in the body, the + means you can add definitions in the environment.It is defined this way:
(define-syntax $+>
  (syntax-rules ()
    ((_ ev)  (let () ev)) ;;  there can be a <+ in it expanding with a 'define'
    ((_ ev ...) (let () ev ...))))

Example:
;; PHASE 0 : eliminate equivalence
;; a <=> b ----> (a => b) and (b => a)
(define (elim-equivalence expr)
  (cond
   ((symbol? expr) expr)
   ((boolean? expr) expr)
   ((isNOT? expr) `(not ,(elim-equivalence (arg expr))))
   ((isIMPLIC? expr) `(=> ,(elim-equivalence (arg1 expr)) ,(elim-equivalence (arg2 expr))))
   ((isEQUIV? expr) ($+> ;; a <=> b ----> (a => b) and (b => a)
                      {a <+ (arg1 expr)} ; definitions, as : (define a (arg1 expr))
                      {b <- (arg2 expr)} ; note: in Racket i could use also <- which auto-define the variable if necessary :
                      {ae <- (elim-equivalence a)}
                      {be <- (elim-equivalence b)}
                      `(and (=> ,ae ,be) (=> ,be ,ae))))
   (else `(,(operator expr) ,(elim-equivalence (arg1 expr)) ,(elim-equivalence (arg2 expr))))))

6.7 Operators and Procedures🔗ℹ

syntax

{n @ m}

Modulo.Same as (modulo n m).

syntax

{n ** m}

Exponentiation.Same as expt.

Note: exponentiation can also be written with superscript numbers and expressions,see after in this document.

syntax

( n)

Square root.Same as sqrt.

( 2)
1.4142135623730951

syntax

( n)

Cubic root.

syntax

{n << m}

Left shift.Same as (arithmetic-shift n m).

syntax

{n >> m}

Right shift.Same as (arithmetic-shift n (- m)).

syntax

{n & m}

Bitwise And

syntax

{n  m}

Bitwise Or.Note: this is U+2223 because vertical line is reserved in Racket.

syntax

{expr1 && expr2}

This is a procedural and intended to be used both internally,inside Scheme+ source code,and externally in a Scheme+ program when parsing is required at runtime where we can not use the macro and and thus we will use the && procedure.Unless your expression will be parsed at runtime do not use it and prefer it and.

syntax

{expr1 ∣∣ expr2}

This is a procedural or.See explanations above.See also note about vertical line reserved in Racket above.

As being procedurals && and ∣∣ are not short-circuited.

syntax

{n  m}

{3  4 < 5}
#t

syntax

{n  m}

;; we plot only in the window
(when {x0  0 and x0  xws  and x1  0 and x1  xws and
       y0  0 and y0  ywsp and y1  0 and y1  ywsp}
    (send dc draw-line
          x0 y0
          x1 y1))

syntax

{n  m}

The same is defined <>.

syntax

{n · m}

Same as *

Note: some Qi operators not documented here (see Qi documentation for them) are recognized, for example ~> should immediately work in infix.

6.8 Superscript🔗ℹ

Superscript characters can be used to form numbers, variable or expressions forming an exponent,thus defining an exponentiation without the need of ** operator:
{2 ³}
(** 2 3) ; parsed expression displayed
8

(define n 3)
{3 ⁻²·⁽ⁿ⁻⁴⁾}
9

Note that alphabetic superscript characters and numeric superscript characters can display at different level of altitude in the browser font system, this is not the case in Emacs editor. Note also that not all alphabetic characters currently exists in superscript, here is the source code definitions:

(define superscript-string "⁻⁺⁰¹²³⁴⁵⁶⁷⁸⁹") ; super script numbers and signs
(define superscript-only-string (string-append superscript-string ; numbers and signs
                                          "ᴬᵃᴮᵇᶜᴰᵈᴱᵉᶠᴳᵍᴴʰᴵᶦᴶʲᴷᵏᴸˡᴹᵐᴺⁿᴼᵒᴾᵖᴿʳˢᵀᵗᵁᵘⱽᵛᵂʷˣʸᶻ" ; note all letters are not available (ex:C,Q,q...)
                                          "⁽⁾"
                                          "⸱" ; will be used as decimal separator
                                          ;; "*" ; multiplication is ambiguous (both super and normal script)
                                          ;; "·" ; another multiplication symbol (but ambiguous too)
                                          "⸍"; division
                                          ))

Note under Linux and on a PC (french) keyboard superscript characters can be generated with the keystroke sequence: ^ n where n is a number or sign.(but this not works for alpha char as it only put some accent on the alpha char)

Superscript also works to write complex numbers exponents:

{3 ⁻²⁺³ᶦ}
(** 3 (+ (- 2) 0+3i)) ; code generated by parser
-0.10979199190468787-0.01707036982454185i

Note that unfortunately for superscript complex number the lower case superscript i does not exist and I is not really a mathematical convention for complex number but you can use the true electrical convention that use the symbol j:

{2 ⁻⁵⁺⁷ʲ}
(** 2 (+ (- 5) 0+7i)) ; code generated by parser
0.004349621840375144-0.03094581215359732i

A last example:
{2-3i ⁻⁵⁺⁷ʲ}
(** 2-3i (+ (- 5) 0+7i)) ; code generated by parser
0.38835198150723493+1.5475077026949722i

6.9 Overloading procedures and operators🔗ℹ

Overloading must be set at a module toplevel, it will not works in a procedure,and there is no need of that. You can provide an overloaded procedure or operator from the module where it is defined and overloaded to other modules.

Different macros and procedures are provided for overloading because of the various type of operator or procedure, operator can be only binary or be n-arity,operators have associativity properties that do not have procedures.Also operators or procedure can preexist in Scheme or you can overload one of your new procedure or operator.All that requires different macros and procedures for overloading that can not be fusioned in a generic macro.

Overloading of operator or procedure is made in two steps:
  1. first we define that a procedure or operator will be overloaded, this will result in creating a new procedure or operator that will be specialized in the next step.

  2. second we overload a procedure or operator by providing a specialized function and some predicates that will be used to test the arguments at runtime.

With this schema we can have a same function (procedure or operator) that will works on different arguments.

Note that we can also extend square bracket [ ] to use different type of object, the same way it is done in the Python language for the angle bracket.This is done by overloading the underlaying procedure that do the bracket apply and the assignment macros,we will see that at the end of this section.

syntax

(define-overload-procedure name)

Define an overloaded procedure named name.

(define-overload-procedure area)

syntax

(overload-procedure name special (predicate ...))

Overload a procedure named name with a specialized procedure named special which use parameters that pass the predicates test.

(define (area-square x) (* x x))
(overload-procedure area area-square (number?))
 
(define (area-rect x y) (* x y))
(overload-procedure area area-rect (number? number?))
 
(area 3)
9
 
(area 2 3)
6

Another example:

(define-overload-procedure uniform)
;; return a number in ]-1,1[
;; the dummy parameter is needed by a flomat procedure
(define (uniform-dummy dummy) {-1 + (random) * 2})
; return a random number between [inf, sup]
(define (uniform-interval inf sup)
  {gap <- sup - inf}
  {inf + gap * (random)})
(overload-procedure uniform uniform-dummy (number?))
(overload-procedure uniform uniform-interval (number? number?))

syntax

(define-overload-existing-procedure name)

Define an overloaded existing procedure named name.
(define-overload-existing-procedure length)

syntax

(overload-existing-procedure name special (predicate ...))

Overload an existing procedure named name with a specialized procedure named special which use parameters that pass the predicates test.

(overload-existing-procedure length vector-length (vector?))
(overload-existing-procedure length string-length (string?))
 
(length #(1 2 3 4))
4
 
(length '(1 2 3))
3
 
(length "abcde")
5

Note that when no defined predicates matches the arguments, in the above example nor vector? nor string? will return true for a list then the overloading schema fall back to the original procedure definition that is here length that works with list.

syntax

(define-overload-operator name)

Define an overloaded operator named name.

syntax

(overload-operator name special (predicate ...))

Overload an operator named name with a specialized operator named special which use parameters that pass the predicates test.

syntax

(define-overload-existing-operator name)

Overload an already existing operator named name with a specialized operator named special which use parameters that pass the predicates test.

(define-overload-existing-operator +)

syntax

(overload-existing-operator name special (predicate ...))

Overload an already existing operator named name with a specialized operator named special which use parameters that pass the predicates test.

(overload-existing-operator + vector-append (vector? vector?))

Now the + append vectors like in Python language:

{#(1 2 3) + #(4 5 6 7)}
'#(1 2 3 4 5 6 7)
 
{(vector 1 2 3) + (vector 4 5 6 7)}
'#(1 2 3 4 5 6 7)
 
;; create an array with 1 in front for the bias coefficient
{z_1 <- #(1) + z[i]} ; + operator has been overloaded to append scheme vectors

syntax

(define-overload-n-arity-operator name)

Define an overloaded n-arity operator named name.

syntax

(overload-n-arity-operator name special (predicate ...))

Overload an n-arity operator named name with a specialized operator named special which use parameters that pass the predicates test.

syntax

(define-overload-existing-n-arity-operator name)

Define an overloaded already existing n-arity operator named name.

(define-overload-existing-n-arity-operator +)

syntax

(overload-existing-n-arity-operator name special (predicate ...))

Overload an already existing n-arity operator named name with a specialized operator named special which use parameters that pass the predicates test.

(define (add-n-lists . vn-lst)
  {map-args <- (cons + vn-lst)}
  (apply map map-args))
 
(overload-existing-n-arity-operator + add-n-lists (list? list?))
 
{'(1 2 3) + '(4 5 6) + '(7 8 9)}
'(12 15 18)
 
(define-overload-existing-operator *)
(define (mult-num-list k v) (map (λ (x) (* k x)) v))
(overload-existing-operator * mult-num-list (number? list?))
{3 * '(1 2 3) + '(4 5 6) + '(7 8 9)}
'(14 19 24)

syntax

(overload-square-brackets getter setter! (pred-obj pred-coord ...))

Overload square bracket [ ] for object that return true with predicate pred-obj with getter for read and setter! for write at coordinates of type validated by predicates pred-coord ....

Example for accessing and modifying a line of a matrix:

(struct matrix-vect (v)) ;; matrix based on vector of vectors
 
(define (matrix-vect-line-ref M lin)
  {v <- (matrix-vect-v M)}
  {v[lin]})
 
 
(define (matrix-vect-line-set! M lin vect-line)
  {v <- (matrix-vect-v M)}
  {v[lin] <- vect-line})
 
(overload-square-brackets matrix-vect-line-ref matrix-vect-line-set! (matrix-vect? number?))
 
(define Mv (matrix-vect #(#(1 2 3) #(4 5 6))))
{Mv[1]}
'#(4 5 6)
 
; define getter,setter
(define (matrix-vect-ref M lin col)
  {v <- (matrix-vect-v M)}
  {v[lin][col]})
 
(define (matrix-vect-set! M lin col x)
  {v <- (matrix-vect-v M)}
  {v[lin][col] <- x})
 
(overload-square-brackets matrix-vect-ref matrix-vect-set!  (matrix-vect? number? number?))
 
{Mv[1][0]}
4

See the full example at https://github.com/damien-mattei/Scheme-PLUS-for-Racket/blob/main/examples/racket/matrix-by-vectors+.rkt

7 Using Makefile and debugging Scheme+ program🔗ℹ

The Racket GUI can not display the line of error in a Scheme+ program.The reason is because the Scheme+ program is pre-parsed by the SRFI 105 reader and the Racket compiler has not access to the original lines of code and even do not display the error line relative to the resulting parsed line of code.

If you have to debug your source code you must generate a Scheme file from your Scheme+ file with curly-infix2prefix4racket in SRFI 105 package and load the result file in Racket GUI. Then you will have all the debug information of Racket on the scheme file.

Another solution is to simply copy/paste the pure Racket code generated by the SRFI 105 Curly Infix parser and run it like a normal Racket program. Again you will have all the information about errors with the true line number displayed.

Another method is to use the Makefile provided:

https://github.com/damien-mattei/Scheme-PLUS-for-Racket/blob/main/examples/racket/Makefile

Put the Makefile in the same place of your Scheme+ program and type in the terminal make. The Makefile will parse all Scheme+ program in the same directory and generate the scheme version in MODULE_DIRECTORY=parsed_files_directory.You can then just load and run the parsed files in Racket GUI to use all the Racket features and tools (macro stepper,etc) for debugging.

Example:

mattei@acer:~/Dropbox/git/Scheme-PLUS-for-Racket/main/Scheme-PLUS-for-Racket/examples/chaos$ ls -la

total 28K

drwxrwxr-x 3 mattei mattei 4,0K sept. 21 17:42 .

drwxrwxr-x 7 mattei mattei 4,0K sept. 26 22:06 ..

-rw-r--r-- 1 mattei mattei  12K sept. 21 17:42 chaos+.rkt

-rw-rw-r-- 1 mattei mattei 1,5K nov.  23  2024 Makefile

drwxrwxr-x 2 mattei mattei 4,0K déc.  16  2024 parsed_files_directory

mattei@acer:~/Dropbox/git/Scheme-PLUS-for-Racket/main/Scheme-PLUS-for-Racket/examples/chaos$ make

PARSING chaos+.rkt :

../../../../../SRFI-105-for-Racket/src/curly-infix2prefix4racket.rkt chaos+.rkt > parsed_files_directory/chaos+.rkt

 

mattei@acer:~/Dropbox/git/Scheme-PLUS-for-Racket/main/Scheme-PLUS-for-Racket/examples/chaos$ ls -la parsed_files_directory/

total 16

drwxrwxr-x 2 mattei mattei 4096 déc.  16  2024 .

drwxrwxr-x 3 mattei mattei 4096 sept. 21 17:42 ..

-rw-r--r-- 1 mattei mattei 6032 sept. 26 22:23 chaos+.rkt

8 Place to find Scheme+ programs and examples🔗ℹ

More examples can be find in this directory and subdirectories:

https://github.com/damien-mattei/Scheme-PLUS-for-Racket/blob/main/examples/

9 Emacs configuration for syntax highligting of Scheme+🔗ℹ

Add the line below in your .emacs configuration file:

(font-lock-add-keywords 'scheme-mode
  '(("\\<\\(define\\|define+\\|def\\|def+\\|return\\|return-rec\\|:=\\|<-\\|condx\\|then\\|else\\)\\>" . font-lock-keyword-face)))

10 Thoughts🔗ℹ

I hope this documentation is not a write-only1 « APL is a write-only language. I can write programs in APL, but I can’t read any of them ». Roy Keir one and will be usefull for any reader.

1 « APL is a write-only language. I can write programs in APL, but I can’t read any of them ». Roy Keir