Bjolang is installed from source only, so the front page says where the source is and links Getting started in the manual. The manual moves to the commit that says the same there. 🤖 Generated with [ECA](https://eca.dev) (anthropic/claude-opus-5-5) Co-Authored-By: eca-agent <git@eca.dev>
87 lines
3.1 KiB
Text
87 lines
3.1 KiB
Text
(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")))
|
|
}
|