summaryrefslogtreecommitdiffhomepage
path: root/janet.html.markdown
blob: 62ed73316c60779b01ed121410a5c9e391516bf2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
---
language: Janet
filename: learnJanet.janet
contributors:
    - ["John Gabriele", "http://www.unexpected-vortices.com/"]
---

[Janet](https://janet-lang.org/) 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](https://janet-lang.org/docs/index.html),
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!

```python
# A comment.

# Some literal values.
true
false
nil

# Typical style for symbols (identifiers-for / names-of things).
do-stuff
pants-on-fire!
foo->bar        # Evidently for converting foos to bars.
fully-charged?
_               # Usually used as a dummy variable.

# Keywords are like symbols that start with a colon, are treated like
# constants, and are typically used as map keys or pieces of syntax in
# macros.
:a
:some-val

# Numbers #####################################################################
5
1e3    # => 1000
1_000  # => 1000
2e-03  # => 0.002
0xff   # => 255

# You can specify a radix (base) like so:
16rff   # => 255 (same as 0xff)
2r1101  # =>  13

# Some numbers in the math library:
math/pi  # => 3.14159
math/e   # => 2.71828

# Strings #####################################################################
"hello"
"hey\tthere"  # contains a tab

# For multi-line strings, use one or more backticks. Backslash-escapes not
# recognized in these (bytes will be parsed literally).
``a long
multi-line
string``    # => "a long\nmulti-line\nstring"

# Strings and data structures in Janet come in two varieties: mutable and
# immutable. The literal for the mutable variety is written with a `@` in
# front of it.

# A mutable string (aka "buffer").
@"this"
@`a multi-line
one here`

(string "con" "cat" "enate")   # => "concatenate"

# To get a substring:
(string/slice "abcdefgh" 2 5)  # => "cde"
# To find a substring:
(string/find "de" "abcdefgh")  # => 3

# See the string library for more (splitting, replacement, etc.)

# Data Structures #############################################################
# Arrays and Tuples
# Arrays are mutable, tuples are immutable.

# Arrays (mutable)
@(4 5 6)
@[4 5 6]

# Tuples (immutable)
# Note that an open paren usually indicates a function call, so if you want a
# literal tuple with parens, you need to "quote" it (with a starting single
# quote mark)...
'(4 5 6)
[4 5 6]  # ... or just use square brackets.

# Tables and Structs (associative data structures)
@{:a 1 :b 2 :c 3}  # table  (mutable)
{:a 1 :b 2 :c 3}   # struct (immutable)

# To "pretty-print" these out, use `pp` instead of `print`.
# More about how to work with arrays/tuples and tables/structs below.

# Bindings ####################################################################
# Bind a value to a symbol.
(def x 4.7)  # Define a constant, `x`.
x            # => 4.7
(quote x)    # => x (the symbol x)
'x           # => x (the symbol x (shorthand))
(print x)    # prints 4.7

# Since we used `def`, can't change to what `x` refers:
(set x 5.6)  # Error, `x` is a constant.

(var y 10)
(set y 12)  # Works, since `y` was defined using `var`.

# Note that bindings are local to the scope they're called in. `let`
# creates a local scope and makes some bindings all in one shot:
(let [a 2
      b 3]
  (print "Hello from inside this local scope.")
  (* a b))  # => 6

# Destructuring is supported, both for arrays/tuples ...
(def a ["foos" "bars" "moos"])
(let [[s1 _ s2] a]
  (print s1 s2))  # foosmoos

# ... and for tables/structs.
(def t {:a "ayy" :b "bee" :c "sea"})
(let [{:a a :b b} t]
  (print a b))  # ayybee

# You can even destructure right in a `def`:
(def [aa1 aa2] a)
aa1  # => foos
aa2  # => bars

(def {:c body-of-water :b insect-friend} t)
body-of-water  # => sea
insect-friend  # => bee

# Note that keywords evaluate to themselves, whereas symbols evaluate
# to whatever value they're bound to (unless you quote them).

# Operators ###################################################################
# Janet supports the usual ensemble of operators.
# +, -, *, /, and so on. Note:
(/ 5 3)  # =>  1.66667
(% 5 3)  # =>  2 (remainder)
(- 5)    # => -5 (or you can just write `-5`)

(++ i)    # increments (modifies `i`)
(-- i)    # decrements
(+= i 3)  # add 3 to `i`
(*= i 3)  # triple `i`
# ... and so on for the other operations on numbers.

# If you don't want to mutate `i`, use `(inc i)` and `(dec i)`.

# Comparison
# =  <  >  not=  <=  >=
(< 2 7 12)  # => true

# Functions ###################################################################
# Call them:
(- 5 3)                   # => 2 (Operators and functions work the same way.)
(math/sin (/ math/pi 2))  # => 1
(range 5)                 # => @[0 1 2 3 4]

# Create them:
(defn mult-by-2
  ``First line of docstring.

  Some more of the docstring.``
  [x]
  (print "Hi.")
  (print "Will compute using: " x)
  (* 2 x))

(print (mult-by-2 6))  # => 12 (after printing "Hi" and so forth)

# If you have a function named "main" in your file, `janet` will automatically
# call it for you when you run the file.

# Interactively read a function's docs from within the repl:
(doc mult-by-2)

# Note, functions have to be defined before they can be used in a function,
# so if you design top-down, you'll need to write your functions from the
# bottom of the file up.

# You can make anonymous functions as well:
(fn [x] (+ x x))
(fn my-func [x] (+ x x))  # This one's less anonymous.

# Use `do` to make some side-effecting calls and then evaluate to
# the last form in the `do`:
(def n (do
         (print "hi")
         (do-some-side-effecting 42)
         3))
n  # => 3

# You might say that function bodies provide an "implicit do".

# Operations on data structures ###############################################
# (Making all of these mutable so we can ... mutate them.)
(def s @"Hello, World!")
(def a @[:a :b :c :d :e])
(def t @{:a 1 :b 2})

(length s)  # => 13
(length a)  # =>  5
(length t)  # =>  2

# Getting values:
(s 7)       # => 87 (which is the code point for "W")
(a 1)       # => :b
(t :a)      # => 1
(keys t)    # => @[:a :b]
(values t)  # => @[1 2]

# Changing values (for mutable data structures):
(put s 2 87)   # @"HeWlo, World!"
(put a 2 :x)   # @[:a :b :x :d :e]
(put t :b 42)  # @{:a 1 :b 42}

# Adding and removing values (again, for mutable data structures):
(buffer/push-string s "??")  # @"HeWlo, World!??"
(array/push a :f)  # @[:a :b :x :d :e :f]
(array/pop a)      # => :f, and it's also removed from `a`.
(put t :x 88)      # @{:a 1 :b 42 :x 88}

# See the manual for a wide variety of functions for working with
# buffers/strings, arrays/tuples, and tables/structs.

# Flow control ################################################################
(if some-condition
  42
  38)

# Only `nil` and `false` are falsey. Everything else is truthy.

(if got-it?
  71)  # No false-branch value. Returns `nil` if `got-it?` is falsey.

(var i 10)
(while (pos? i)
  (print "... " i)
  (-- i))
# Now `i` is 0.

# `case` compares the dispatch value to each of the options.
(var x 2)
(case x
  1 "won"
  2 "too"
  3 "tree"
  "unknown")  # => "too"

# `cond` evaluates conditions until it gets a `true`.
(set x 8)
(cond
  (= x 1) "won"
  (= x 2) "too"
  (< x 10) "tree"
  "oof!")  # => "tree"

(when (avoided-wipeout?)
  (do-side-effecty-thing 88)
  (smell-the-roses)
  (paint-fencepost-error))

# Pattern matching.
# `match` is like a high-powered switch expression. If you switch on a data
# structure, it can look inside to try and match on its contents. For example,
# matching on a table or struct:
(def t {:a 1 :b 2 :c 3})
(match t
  {:yar v} (print "matches key :yar! " v)
  {:moo v} (print "matches key :moo! " v)
  {:c   v} (print "matches key :c! "   v)
  _        (print "no match"))             # => prints "matches key :c! 3"

# Iterating ###################################################################
# Iterate over an integer range:
(for i 0 5
  (print i))  # prints 0, 1, 2, 3, 4

# There's also the more general `loop`:
(loop [i :range [0 10] :when (even? i)]
  (print i))

# Loop over an array/tuple:
(def words ["foo" "bar" "baz"])
(each word words
  (print word))

# Loop over a table/struct:
(def t {:a 1 :b 2})
(eachp [k v] t  # Loop over each pair in `t`.
  (print k " --> " v))

# Can also use `eachk` to loop over keys in a table or struct.

# Functional programming ######################################################
# You'll find many familiar old friends here.
(filter even?
        (map (fn [x]
               (* x x))
             (range 10)))  # => @[0 4 16 36 64]

(reduce + 0 (range 5))     # => 10

# ...and lots more (see the API docs).

# Errata ######################################################################
(type a)                # => the type of `a` (as a keyword)
(describe a)            # => a human-readable description of `a`
(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](https://janet-lang.org/docs/index.html) and the [Janet API
docs](https://janet-lang.org/api/index.html) for more info.