Janet

Личный сайт Go-разработчика из Казани

Janet is a Lisp-like (Clojure-like), lexically-scoped, dynamically-typed, garbage-collected, C-based, high-level language. The entire language (core library, interpreter, compiler, assembler, PEG) is about 300-500 kB and should run on many constrained systems.

I encourage you to try out the code snippets below in the Janet repl (either by installing Janet, or else by using the repl embedded in the Janet homepage).

As we only have a scant y minutes, we’ll survey the basics here and leave the remaining details for the manual. So please, keep your arms and legs inside the vehicle at all times, and on with the scenic tour!

1# A comment. 2 3# Some literal values. 4true 5false 6nil 7 8# Typical style for symbols (identifiers-for / names-of things). 9do-stuff 10pants-on-fire! 11foo->bar # Evidently for converting foos to bars. 12fully-charged? 13_ # Usually used as a dummy variable. 14 15# Keywords are like symbols that start with a colon, are treated like 16# constants, and are typically used as map keys or pieces of syntax in 17# macros. 18:a 19:some-val 20 21# Numbers ##################################################################### 225 231e3 # => 1000 241_000 # => 1000 252e-03 # => 0.002 260xff # => 255 27 28# You can specify a radix (base) like so: 2916rff # => 255 (same as 0xff) 302r1101 # => 13 31 32# Some numbers in the math library: 33math/pi # => 3.14159 34math/e # => 2.71828 35 36# Strings ##################################################################### 37"hello" 38"hey\tthere" # contains a tab 39 40# For multi-line strings, use one or more backticks. Backslash-escapes not 41# recognized in these (bytes will be parsed literally). 42``a long 43multi-line 44string`` # => "a long\nmulti-line\nstring" 45 46# Strings and data structures in Janet come in two varieties: mutable and 47# immutable. The literal for the mutable variety is written with a `@` in 48# front of it. 49 50# A mutable string (aka "buffer"). 51@"this" 52@`a multi-line 53one here` 54 55(string "con" "cat" "enate") # => "concatenate" 56 57# To get a substring: 58(string/slice "abcdefgh" 2 5) # => "cde" 59# To find a substring: 60(string/find "de" "abcdefgh") # => 3 61 62# See the string library for more (splitting, replacement, etc.) 63 64# Data Structures ############################################################# 65# Arrays and Tuples 66# Arrays are mutable, tuples are immutable. 67 68# Arrays (mutable) 69@(4 5 6) 70@[4 5 6] 71 72# Tuples (immutable) 73# Note that an open paren usually indicates a function call, so if you want a 74# literal tuple with parens, you need to "quote" it (with a starting single 75# quote mark)... 76'(4 5 6) 77[4 5 6] # ... or just use square brackets. 78 79# Tables and Structs (associative data structures) 80@{:a 1 :b 2 :c 3} # table (mutable) 81{:a 1 :b 2 :c 3} # struct (immutable) 82 83# To "pretty-print" these out, use `pp` instead of `print`. 84# More about how to work with arrays/tuples and tables/structs below. 85 86# Bindings #################################################################### 87# Bind a value to a symbol. 88(def x 4.7) # Define a constant, `x`. 89x # => 4.7 90(quote x) # => x (the symbol x) 91'x # => x (the symbol x (shorthand)) 92(print x) # prints 4.7 93 94# Since we used `def`, can't change to what `x` refers: 95(set x 5.6) # Error, `x` is a constant. 96 97(var y 10) 98(set y 12) # Works, since `y` was defined using `var`. 99 100# Note that bindings are local to the scope they're called in. `let` 101# creates a local scope and makes some bindings all in one shot: 102(let [a 2 103 b 3] 104 (print "Hello from inside this local scope.") 105 (* a b)) # => 6 106 107# Destructuring is supported, both for arrays/tuples ... 108(def a ["foos" "bars" "moos"]) 109(let [[s1 _ s2] a] 110 (print s1 s2)) # foosmoos 111 112# ... and for tables/structs. 113(def t {:a "ayy" :b "bee" :c "sea"}) 114(let [{:a a :b b} t] 115 (print a b)) # ayybee 116 117# You can even destructure right in a `def`: 118(def [aa1 aa2] a) 119aa1 # => foos 120aa2 # => bars 121 122(def {:c body-of-water :b insect-friend} t) 123body-of-water # => sea 124insect-friend # => bee 125 126# Note that keywords evaluate to themselves, whereas symbols evaluate 127# to whatever value they're bound to (unless you quote them). 128 129# Operators ################################################################### 130# Janet supports the usual ensemble of operators. 131# +, -, *, /, and so on. Note: 132(/ 5 3) # => 1.66667 133(% 5 3) # => 2 (remainder) 134(- 5) # => -5 (or you can just write `-5`) 135 136(++ i) # increments (modifies `i`) 137(-- i) # decrements 138(+= i 3) # add 3 to `i` 139(*= i 3) # triple `i` 140# ... and so on for the other operations on numbers. 141 142# If you don't want to mutate `i`, use `(inc i)` and `(dec i)`. 143 144# Comparison 145# = < > not= <= >= 146(< 2 7 12) # => true 147 148# Functions ################################################################### 149# Call them: 150(- 5 3) # => 2 (Operators and functions work the same way.) 151(math/sin (/ math/pi 2)) # => 1 152(range 5) # => @[0 1 2 3 4] 153 154# Create them: 155(defn mult-by-2 156 ``First line of docstring. 157 158 Some more of the docstring.`` 159 [x] 160 (print "Hi.") 161 (print "Will compute using: " x) 162 (* 2 x)) 163 164(print (mult-by-2 6)) # => 12 (after printing "Hi" and so forth) 165 166# If you have a function named "main" in your file, `janet` will automatically 167# call it for you when you run the file. 168 169# Interactively read a function's docs from within the repl: 170(doc mult-by-2) 171 172# Note, functions have to be defined before they can be used in a function, 173# so if you design top-down, you'll need to write your functions from the 174# bottom of the file up. 175 176# You can make anonymous functions as well: 177(fn [x] (+ x x)) 178(fn my-func [x] (+ x x)) # This one's less anonymous. 179 180# Use `do` to make some side-effecting calls and then evaluate to 181# the last form in the `do`: 182(def n (do 183 (print "hi") 184 (do-some-side-effecting 42) 185 3)) 186n # => 3 187 188# You might say that function bodies provide an "implicit do". 189 190# Operations on data structures ############################################### 191# (Making all of these mutable so we can ... mutate them.) 192(def s @"Hello, World!") 193(def a @[:a :b :c :d :e]) 194(def t @{:a 1 :b 2}) 195 196(length s) # => 13 197(length a) # => 5 198(length t) # => 2 199 200# Getting values: 201(s 7) # => 87 (which is the code point for "W") 202(a 1) # => :b 203(t :a) # => 1 204(keys t) # => @[:a :b] 205(values t) # => @[1 2] 206 207# Changing values (for mutable data structures): 208(put s 2 87) # @"HeWlo, World!" 209(put a 2 :x) # @[:a :b :x :d :e] 210(put t :b 42) # @{:a 1 :b 42} 211 212# Adding and removing values (again, for mutable data structures): 213(buffer/push-string s "??") # @"HeWlo, World!??" 214(array/push a :f) # @[:a :b :x :d :e :f] 215(array/pop a) # => :f, and it's also removed from `a`. 216(put t :x 88) # @{:a 1 :b 42 :x 88} 217 218# See the manual for a wide variety of functions for working with 219# buffers/strings, arrays/tuples, and tables/structs. 220 221# Flow control ################################################################ 222(if some-condition 223 42 224 38) 225 226# Only `nil` and `false` are falsey. Everything else is truthy. 227 228(if got-it? 229 71) # No false-branch value. Returns `nil` if `got-it?` is falsey. 230 231(var i 10) 232(while (pos? i) 233 (print "... " i) 234 (-- i)) 235# Now `i` is 0. 236 237# `case` compares the dispatch value to each of the options. 238(var x 2) 239(case x 240 1 "won" 241 2 "too" 242 3 "tree" 243 "unknown") # => "too" 244 245# `cond` evaluates conditions until it gets a `true`. 246(set x 8) 247(cond 248 (= x 1) "won" 249 (= x 2) "too" 250 (< x 10) "tree" 251 "oof!") # => "tree" 252 253(when (avoided-wipeout?) 254 (do-side-effecty-thing 88) 255 (smell-the-roses) 256 (paint-fencepost-error)) 257 258# Pattern matching. 259# `match` is like a high-powered switch expression. If you switch on a data 260# structure, it can look inside to try and match on its contents. For example, 261# matching on a table or struct: 262(def t {:a 1 :b 2 :c 3}) 263(match t 264 {:yar v} (print "matches key :yar! " v) 265 {:moo v} (print "matches key :moo! " v) 266 {:c v} (print "matches key :c! " v) 267 _ (print "no match")) # => prints "matches key :c! 3" 268 269# Iterating ################################################################### 270# Iterate over an integer range: 271(for i 0 5 272 (print i)) # prints 0, 1, 2, 3, 4 273 274# There's also the more general `loop`: 275(loop [i :range [0 10] :when (even? i)] 276 (print i)) 277 278# Loop over an array/tuple: 279(def words ["foo" "bar" "baz"]) 280(each word words 281 (print word)) 282 283# Loop over a table/struct: 284(def t {:a 1 :b 2}) 285(eachp [k v] t # Loop over each pair in `t`. 286 (print k " --> " v)) 287 288# Can also use `eachk` to loop over keys in a table or struct. 289 290# Functional programming ###################################################### 291# You'll find many familiar old friends here. 292(filter even? 293 (map (fn [x] 294 (* x x)) 295 (range 10))) # => @[0 4 16 36 64] 296 297(reduce + 0 (range 5)) # => 10 298 299# ...and lots more (see the API docs). 300 301# Errata ###################################################################### 302(type a) # => the type of `a` (as a keyword) 303(describe a) # => a human-readable description of `a` 304(string/format "%j" a) # => Janet values, nicely-formatted

This tour didn’t cover a number of other features such as modules, fibers, PEGs, macros, etc., but should give you a taste of what Janet is like. See the Janet manual and the Janet API docs for more info.

Also check out Janet for Mortals for an in-depth ebook on Janet.