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.