(meta (title "Bjolang") (listing? #f)) @div["logo"]{@image["/_resources/logo.svg" #:alt "Bjolang"]} Bjolang is a Lisp for .NET. It has types that are inferred, unions that are matched exhaustively, traits, hygienic macros, and bjoroutines, and it compiles to C#. It is a small experiment in what I would like in a programming language, and in api design. I built it with liberal use of ai, so beware. @codeblock[#:lang "bjolang"]|{ (type (: Shape (Union (: Circle double) (: Rect double double)))) (: area (-> Shape double)) (defun (area shape) (match shape ((Circle r) (* 3.14159 (* r r))) ((Rect w h) (* w h)))) (defun (main args) (loop (:for s [(Circle 1.0) (Rect 2.0 3.0)]) (:do (println #"area: ${(area s)}"))) 0) }| Bjolang is installed from source only. The code is at @link["https://github.com/bjoli/Bjolang"]{github.com/bjoli/Bjolang}, and @link["manual/manual.html#getting-started"]{Getting started} says how to build it. @link["manual/"]{Read the manual}, or go straight to the @link["manual/modules/"]{library reference}. @section{more examples} ConcurrentML brings the multithreading story for bjolang into the 1990s. The function within cannot be written in go, because select is a statement. @codeblock[#:lang "bjolang"]{ (: within (-> int (Event %a) (Event (Option %a)))) (defun (within ms ev) (choose (wrap ev #(Some &)) (wrap (timeout ms) (fun (u) None)))) (sync (within 20 (chan-recv kitchen))) ;; => None, and nothing is consumed (sync (within 500 (chan-recv kitchen))) ;; => (Some "dinner") (sync (within 20 (spawn-evt (count-to 1000)))) ;; works on fibers too } This sums every line and every char read from stdin. When the port is closed, the result is printed using the show function from (std fmt). @codeblock[#:lang "bjolang"]{ (import (only (std ports) port->seq)) (import (std fmt)) (defun (main args) (def line-seq (port->seq read-line (deref current-input-port))) (loop (:for line line-seq) (:acc lines (summing 1)) ;; Any :for after a non-:for clause opens a new subloop ;; so this loops over ever char in the line. (:for ch line) (:acc chars (summing 1) :when (not (char-whitespace? ch))) => (show [(tabular [["Lines:" nl "Chars:" nl] [lines nl chars nl]])])) 0) } Here is a small example showing off bjoroutine use together with process pipelines @codeblock[#:lang "bjolang"]{ (import (std run)) ;; this is an asynchronous filter that suspends if the read-char/opt or ;; write-char has to wait. A filter is a function type declared in (std run) ;; this particular filter upcases every letter. (: shout Filter) (defbjo (shout in out) (loop (:for ch (in-port in read-char/opt)) (:do (write-char out (char-upcase ch))))) ;; the run/xyz functions uses type elaboration to allow for ;; simple DSLs using quoted lists. This runs cat (the linux binary) ;; pipes it's output to the shout method and pipes that to a grep after ;; the word BOMB. (run/string '(pipe (cat "notes.txt") ,shout (grep "BOMB"))) }