www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | LICENSE

demo2-rkt.hl.rkt (6900B)


      1 #lang hyper-literate #:꩜ envlang/rkt
      2 
      3 ꩜title[#:tag "racketfest"]{Envlang @ racketfest}
      4 
      5 ꩜section{Use cases for macros}
      6 
      7 ꩜subsection{Environment manipulation}
      8 
      9 Adding bindings to the environment, getting bindings from the environment:
     10 
     11 ꩜chunk[<use-case-bindings>
     12        (let (var val) body)             ;; env += {var = val}
     13        (define-struct name (field ...)) ;; env += {"$name-$field" = accessor-fn} …
     14        (aif condition if-true if-false) ;; env += {it = condition}
     15        (match v [(cons a b) body])      ;; env += {a = (car v)} {b = (cdr v)}
     16        ]
     17 
     18 ꩜subsection{Control flow}
     19 
     20 Changing the order of execution:
     21 
     22 ꩜chunk[<use-case-order>
     23        (if condition if-true if-false)
     24        ;; can be expressed as:
     25        (force (if condition
     26                   (λ () if-true)
     27                   (λ () if-false)))
     28 
     29        (match v ([null if-null] [(cons a b) if-cons]))
     30        ;; can be expressed as:
     31        (force (if (null? v)
     32                   (λ () if-null)
     33                   (λ () (let ([a (car v)] [b (cdr v)]) if-cons))))
     34        
     35        (for/list ([x (in-list l)]) body)
     36        ;; can be expressed as
     37        (map (λ (x) body) l)
     38        ]
     39 ꩜subsection{Syntactic sugar}
     40 
     41 ꩜chunk[<use-case-syntactic-sugar>
     42        (1 + 2 * 3) ;; infix
     43        (let x = 3 in (+ x 1))
     44        (for/list x in (list 1 2 3) (+ x 1))
     45        (let x:int = 3 in (+ x 1))]
     46 
     47 ꩜subsection{Optimisations}
     48 
     49 Optimisations are semantics-preserving compile-time transformations of the program.
     50 
     51 ꩜chunk[<use-case-optimisations>
     52        pre-calculated hash table
     53        loop unrolling
     54        …]
     55 
     56 ꩜subsection{Code analysis}
     57 
     58 Tracking and propagating annotations on the code:
     59 
     60 ꩜chunk[<use-case-annotations>
     61        typed/racket
     62        source locations
     63        tooltips]
     64 
     65 ꩜section{Overview of the semantics}
     66 
     67 ꩜chunk[<promise>
     68        (f arg ...)
     69        ;; is sugar for:
     70        (@ f env (⧵ (env) arg) ...)]
     71 
     72 ꩜chunk[<variables>
     73        x
     74        ;; is sugar for:
     75        (hash-ref env x)]
     76 
     77 ꩜section{First-class solutions}
     78 
     79 Adding bindings to the environment, getting bindings from the environment:
     80 
     81 ꩜subsection{Environment manipulation}
     82 
     83 User-defined let:
     84 
     85 ꩜chunk[<my-let>
     86        (⧵ outer-env (var val body)
     87           ;; evaluate body in outer env + var=val
     88           (force (hash-set outer-env
     89                            ;; var name
     90                            (promise->string var)
     91                            ;; evaluate val in outer env
     92                            (force outer-env val))
     93                  body))]
     94 
     95 User-defined let with different order for the arguments:
     96 
     97 ꩜chunk[<use-return+where>
     98        (return (+ x 1)
     99                where x = 123)]
    100 
    101 ꩜chunk[<return+where>
    102        (⧵ outer-env (body kw-where var kw-= val)
    103           (assert (string=? (promise->string kw-where) "where"))
    104           (assert (string=? (promise->string kw-=)     "="))
    105           (@ my-let outer-env var val body))]
    106 
    107 ꩜subsection{Control flow}
    108 
    109 ꩜chunk[<my-if>
    110        (⧵ outer-env (condition if-true if-false)
    111           (force env ((force env condition) if-true if-false)))]
    112 
    113 ꩜subsection{Syntactic sugar}
    114 
    115 ꩜subsubsection{Identifiers with different meanings}
    116 
    117 Bindings in the environment point to a table associating
    118 meanings to values. See ꩜racketmodname[polysemy].
    119 
    120 ꩜chunk[<variables>
    121        x
    122        ;; becomes sugar for:
    123        (hash-ref (hash-ref env x) "variable")]
    124 
    125 ꩜racket[in] keyword used in different contexts:
    126 
    127 ꩜chunk[<let-in-usage>
    128        (let x = 3 in (+ x 1))]
    129 
    130 ꩜chunk[<let-in>
    131        (⧵ outer-env (var kw-= val kw-in body)
    132           (assert (equal? (hash-ref (hash-ref env (promise->string kw-=))
    133                                     "let-in keyword")
    134                           let-in-=))
    135           (assert (equal? (hash-ref (hash-ref env (promise->string kw-in))
    136                                     "let-in keyword")
    137                           let-in-in))
    138           (@ my-let outer-env var val body))]
    139 
    140 ꩜chunk[<for-in-usage>
    141        (for/list x in (list 1 2 3) (+ x 1))]
    142 
    143 ꩜chunk[<for-in>
    144        (⧵ outer-env (var kw-in lst body)
    145           (assert (equal? (hash-ref (hash-ref env (promise->string kw-in))
    146                                     "for keyword")
    147                           for-in))
    148           (@ map outer-env  var val body))]
    149 
    150 It's easy to rename just the ꩜racket["let-in keyword"] part
    151 without renaming the ꩜racket["for keyword"] part.
    152 
    153 ꩜subsubsection{Extra parentheses}
    154 
    155 ꩜chunk[<use-let-paren>
    156        (let [x 2]
    157          (+ x 1))]
    158 
    159 ꩜chunk[<let-paren>
    160        (⧵ outer-env (binding body)
    161           (let varval (force (hash-set "#%app" cons) binding)
    162             (@ my-let outer-env (car varval) (cadr varval) body)))]
    163 
    164 ꩜subsubsection{Infix}
    165 
    166 ꩜chunk[<example-infix>
    167        (1 + 2 * 3)]
    168 
    169 Needs external support in the language (or overloading
    170 ꩜racket[#%app]). WIP prototype using
    171 ꩜link["http://www.cse.chalmers.se/~nad/publications/danielsson-norell-mixfix.pdf" "mixfix"]
    172 on ꩜link["https://repl.it/@envlang/env"]{repl.it} and
    173 ꩜link["https://github.com/envlang/env"]{github}.
    174 
    175 ꩜subsubsection{Manipulating identifiers}
    176 
    177 ꩜chunk[<example-postfix-ids>
    178        (let x:int = 3 in (+ x 1))]
    179 
    180 ꩜chunk[<postfix-ids>
    181        (⧵ outer-env (var kw-= val kw-in body)
    182           (let ([forced-val (force outer-env val)])
    183             (when (ends-with (promise->string var) ":int")
    184               (assert int? forced-val))
    185             (@ my-let outer-env var val body)))]
    186 
    187 ꩜section{Compile-time transformations}
    188 
    189 Wrap parts to be evaluated at compile-time, the wrapper acts
    190 like ꩜racket[unquote] where the whole program is in a
    191 ꩜racket[quasiquote].
    192 
    193 ꩜chunk[<compile-time-proposal>
    194        (run-time
    195         (let ([x (compile-time (+ 1 2 3))])
    196           (* x x)))]
    197 
    198 ꩜chunk[<compile-time-proposal-equivalent>
    199        `(let ([x ,(+ 1 2 3)])
    200           (* x x))]
    201 
    202 Semantics-preserving: removing the ꩜racket[run-time] and
    203 ꩜racket[compile-time] markers must give an equivalent
    204 program.
    205 
    206 ꩜section{Code analysis}
    207 
    208 ꩜subsection{Type checking}
    209 
    210 These environment manipulations can be modeled with row types:
    211 
    212 ꩜chunk[<row-type-example>
    213        (λ (x : (struct [foo : int] [bar : string] . ρ))
    214          : (struct [foo : int] [quux : int] . ρ)
    215          (x without .bar
    216             with .quux = (+ x.foo (string->int x.bar))))]
    217 
    218 
    219 ꩜subsection{Implemented within the language}
    220 
    221 … to be explored?
    222 
    223 ꩜section{Example use}
    224 
    225 ꩜chunk[<program>
    226        (my-let x 3
    227          (let-paren [x 3]
    228            (let-postfix x:int = 3 in
    229              (return (for/list z in (compile-time (list 1 2 3))
    230                        (+ z y))
    231                      where y = (+ 1 x)))))]
    232 
    233 
    234 ꩜chunk[<env+program>
    235        (let* ([my-let <my-let>]
    236               [return <return+where>]
    237               [my-if <my-if>]
    238               [let-paren <let-paren>]
    239               [let-postfix <postfix-ids>]
    240               )
    241          <program>)]
    242 
    243 ꩜chunk[<*>
    244        ;;<env+program>
    245        ]