JanetDocsSourcePlaygroundTutorialsI'm Feeling luckyCommunityGitHub sign in

Community documentation for Janet

Supported Modules

Welcome, I'm happy to see you here! Feel free to add a happy example, the more the merrier!

Loading...

Recent Examples

# By default, top level defs can be optimized better:
(defn let-sum [] (let [a 1 b 2 c 3] (+ a b c)))
(def a 1)
(def b 2)
(def c 3)
(defn top-def-sum []  (+ a b c))

(disasm let-sum)     # (ldi 0 1) (ldi 1 2) (ldi 2 3) (add 3 0 1) (add 3 3 2)
(disasm top-def-sum) # (ldi 0 1) (addim 1 0 2) (addim 1 1 3)

# But with *optimize* level 3, they are both better
# n.b. func must be (re)defined after *optimize* is set
(setdyn *optimize* 3)
(defn let-sum [] (let [a 1 b 2 c 3] (+ a b c)))
(defn top-def-sum []  (+ a b c))

(disasm let-sum)     # (ldi 0 6)
(disasm top-def-sum) # (ldi 0 6)

# currently, implemented optimizations are mostly in 1 and 2
*optimize*veqqqPlayground
# Janet numbers are "doubles" representing each int up to 2^53 (9007199254740992)
# Above this, they can't, so these both eval to the same thing!
(math/exp2 53)
(+ 1 (math/exp2 53))


# After 2^53, doubles only represent even numbers
# Janet prints numbers above 2^53 in exponent form, hiding the end
(+ 2 (math/exp2 53)) # 9.00719925474099e+15

# But the odd numbers round interestingly!
# 2^53 + 2, 2^53 + 4 etc. are slots. We choose which to round e.g. 2^53 + 3 into.
# In school, we round .5 up, doubles above 2^53  round .5 to the neighbor divisible by 4!
(def p53 (math/exp2 53))
(= (+ p53 1) p53) # true
(= (+ p53 2) p53) # false
(= (+ p53 1) (+ p53 2)) # false
(= (+ p53 3) (+ p53 2)) # false
(= (+ p53 3) (+ p53 4)) # true
(= (+ p53 5) (+ p53 4)) # true
(= (+ p53 5) (+ p53 6)) # false
(= (+ p53 7) (+ p53 8)) # true
(= (+ p53 9) (+ p53 8)) # true

# After 2^54, it's the neighbor divisible by 8.
# After 2^55, it's the neighbor divisible by 16!
# It continues this way until 2^1024, which overflows to infinity
(= math/inf (math/exp2 1024)) # true
math/exp2veqqqPlayground
# If you have a working project.janet file, you can use it from janet-pm with just this:
(import spork/declare-cc)

(dofile "project.janet" :env (declare-cc/jpm-shim-env))
spork/declare-cc/jpm-shim-envveqqqPlayground
(let (sinlu (array/new 10))  # 10 element look up table.
  (for i 0 10 (put sinlu i (math/sin (* math/pi (/ i 10)))))
  (pp sinlu))
array/newoofoePlayground
(let (x @["This" "is" "a"]     # Must be array.
      y @["test" "of"]       
      z  ["the" "emergency!"])  # Tuple OK for part.
  (pp (array/join x y z)))

# @["This" "is" "a" "test" "of" "the" "emergency!"]
array/joinoofoePlayground
(import spork/json)
(def input `` {"name": "person", "unknown": null, "happy": true, "sad": false} ``)

When calling, the json dictionary becomes a mutable table in janet.

(json/decode input)
@{"happy" true "name" "person" "sad" false "unknown" :null}

pass `true` as the first arg, and json keys become janet keywords.

(json/decode input true)
@{:happy true :name "person" :sad false :unknown :null}

pass `true` as the second arg, and json keys that map to `null` are not hydrated.

(json/decode input true true)
@{:happy true :name "person" :sad false}



spork/json/decodenickfunPlayground
(print "The build hash of your Janet executable is " janet/build ".")
janet/buildoofoePlayground
# Janet v1.42.0 -- See %src/include/janet.h.
(defn set? [position] (["not set" "set"] (band janet/config-bits position)))
(printf ```
Configurations:
* NANBOX %s.
* SINGLE_THREADED %s.
* NANBOX_64_POINTER_SHIFT %s.``` (set? 0x1) (set? 0x2) (set? 0x4))
janet/config-bitsoofoePlayground
(def cc (ev/thread-chan 99))  # Sets up a message channel.
(def ww (filewatch/new cc))   # Creates the watcher.
(filewatch/add ww "ftest.janet" :all)     # Watch for all changes.
(filewatch/add ww "fadd.janet"  :modify)  # Only care if modified.
(filewatch/listen ww)         # Start filewatcher listening for changes.

# Note that we may still get events for files that have been removed
# so we have to make sure we don't remove them twice.

(var careless "Have we already removed %fadd.janet?" false)
(forever
 (let (item (ev/take cc))
   (pp (ev/take cc))
   (when (and (not careless) (= "fadd.janet" (item :wd-path)))
     (print "I don't care about this file anymore.")
     (filewatch/remove ww (item :wd-path))
     (set careless true)
     )))
filewatch/removeoofoePlayground
(def cc (ev/thread-chan 99))  # Sets up a message channel.
(def ww (filewatch/new cc))   # Creates the watcher.
(filewatch/add ww "ftest.janet" :all)     # Watch for all changes.
(filewatch/add ww "fadd.janet"  :modify)  # Only care if modified (Linux-specific flag).
(filewatch/listen ww)         # Start filewatcher listening for changes.

(pp (ev/take cc))             # Print info on first file to change.
(filewatch/unlisten ww)       # Stop caring about changes.
filewatch/addoofoePlayground
(def cc (ev/thread-chan 99))  # Sets up a message channel.
(def ww (filewatch/new cc))   # Creates the watcher.
(filewatch/add ww "ftest.janet" :all)     # Watch for all changes.
(filewatch/add ww "fadd.janet"  :modify)  # Only care if modified.
(filewatch/listen ww)         # Start filewatcher listening for changes.

(pp (ev/take cc))             # Print info on first file to change.
(filewatch/unlisten ww)       # Stop caring about changes.
                              # This allows the program to exit -- otherwise
                              # filewatcher listening thread keeps running.
filewatch/unlistenoofoePlayground
(def cc (ev/thread-chan 99))  # Sets up a message channel.
(def ww (filewatch/new cc))   # Creates the watcher.
(filewatch/add ww "ftest.janet" :all)  # File to watch.
(filewatch/listen ww)         # Start filewatcher listening for changes.

(ev/spawn-thread              # Spawn thread to catch change events.
 (print "Waiting...")
 (forever (pp (ev/take cc))))
filewatch/listenoofoePlayground
(def cc (ev/thread-chan 99))  # Sets up a message channel.
(def ww (filewatch/new cc))   # Creates the watcher.
(filewatch/add ww "ftest.janet" :all)  # File to watch.
(filewatch/listen ww)         # Start filewatcher listening for changes.

(ev/spawn-thread              # Spawn thread to catch change events.
 (print "Waiting...")
 (forever (pp (ev/take cc))))
filewatch/newoofoePlayground
(when (def x 10)
  (string "Got value: " x))
# "Got value: 10"

(when (def x nil)
  (string "Got value: " x))
# nil
whenyohannd1Playground
# Since table/clone produces a shallow copy and composing freeze and thaw makes everything mutable/immutable
(defn deep-clone [ds]
  (prewalk
    |(cond
       (table? $) (table/clone $)
       (array? $) (array/slice $)
       (buffer? $) (buffer/slice $)
       $)
  ds))
# CalebF wrote this: https://janet.zulipchat.com/#narrow/channel/409517-help/topic/table.2Fclone.20doesn.27t.20make.20a.20deep.20copy.3F/near/617675442
prewalkveqqqPlayground
(import spork/misc)
(def d (misc/capout (doc misc/capout)))

d # returns:
@"\n\n    macro\n    /usr/local/lib/janet/spork/misc.janet on 
line 340, column 1\n\n    \e[97m(capout & body)\e[39m\n\n   
 Captures the standard output of the variadic \e[97mbody\e[39m
 and returns it as \n    a buffer.\n\n\n"
spork/misc/capoutveqqqPlayground
# Get all matches, similar to a global regular expression

(peg/match '(any (+ (<- :a+) 1)) "Hello, world!")
# => @["Hello" "world"]

(peg/match '(any (+ (number :d) 1)) "1A2B3C4D5")
# => @[1 2 3 4 5]

(peg/match '(any (+ (<- :a+) 1)) "12345")
# => @[]
peg/matchTheLastZombiePlayground
(mapcat
  |[$0 $1 (* $0 $1)]
  [1 2 3]
  [100 200 300])
# => @[1 100 100 2 200 400 3 300 900]
mapcattaoeffectPlayground
# If your tooling or the compiler doesn't believe a symbol will be bound e.g.:
(def a b) # if b e.g. gets bound by some macro or pushed directly to the env

# You can wrap it with compwhen on a bool:
(var- bla false)
(compwhen bla
          (def a b))

# Whatever defines b should then set bla to true
# From: https://codeberg.org/veqq/declarative-dsls/src/branch/master/src/declarative-dsls/logic.janet
compwhenveqqqPlayground
# To make a package conditionally export from another:

# A package can see whether another module was already imported,
# and conditionally act and e.g. import it and rebind/export some symbols:
(var- bla false)
(compwhen  (not (some |(string/has-suffix? "dataframes.janet" $) (keys module/cache)))
           (import declarative-dsls/dataframes :as "no" :export false)
           (set bla true))
(compwhen bla
          (def print-as-table no/print-as-table)
          (def select no/select)
          (def populate-df! no/populate-df!)
          (def rows->dataframe no/rows->dataframe)
          (def dataframe->rows no/dataframe->rows))

# From: https://codeberg.org/veqq/declarative-dsls/src/branch/master/src/declarative-dsls/logic.janet
importveqqqPlayground