diff options
| -rw-r--r-- | janet.html.markdown | 328 | 
1 files changed, 328 insertions, 0 deletions
| diff --git a/janet.html.markdown b/janet.html.markdown new file mode 100644 index 00000000..755a0fc9 --- /dev/null +++ b/janet.html.markdown @@ -0,0 +1,328 @@ +--- +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! + +```janet +# 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. No escapes allowed. +``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.) + +# 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 (AKA: "maps", "hashmaps", "dictionaries") +@{:a 1 :b 2 :c 3}  # table  (mutable) +{:a 1 :b 2 :c 3}   # struct (immutable) + +# More about how to work with arrays/tuples and tables/structs below. + +# Bindings #################################################################### +# ... or "Name Some Things!" (that is, 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 made 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 +(-- i)    # decrements +(+= i 3)  # add 3 to `i` +(*= i 3)  # triple `i` +# ... and so on for the other operations on numbers. + +# Comparison +# =  <  >  not=  <=  >= +(< 2 7 12)  # => true + +# Functions ################################################################### +# Call them: +(- 5 3)  # => 2 (Yes, operators and functions work the same.) +(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. + +  Possibly more!``` +  [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 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 & 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/struct. + +# 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. | 
