JanetDocsSourcePlaygroundTutorialsI'm Feeling luckyCommunityGitHub sign in

Community documentation for Janet

Supported Modules

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

Loading...

Random Examples

# Flatten single level of nested collections

(def foo [ [[1 2] [3 4]]   
           [[5 6] [7 8]] ])

(apply array/concat @[] foo) # => @[(1 2) (3 4) (5 6) (7 8)]
array/concatmaradPlayground
(math/hypot 5 12)
# => 13
math/hypotsogaiuPlayground
(if-let [x true 
         y (not x)]
  :a
  :b)
# => :b
if-letsogaiuPlayground
(loop [i :range [0 12]]
  (print i))

# => 0
# => 1
# => 2
# => 3
# => 4
# => 5
# => 6
# => 7
# => 8
# => 9
# => 10
# => 11
# => nil

loopjgartePlayground
(eachp [k v] {:a "a val" :b "b val" :c "c val"} (print k " - " v))
# prints c - c val
# prints a - a val
# prints b - b val
eachppepePlayground
(buffer/format @"0 - 1 = " "%d" -1)
# =>
@"0 - 1 = -1"
buffer/formatsogaiuPlayground
(let [a 1 b 2 c 3] (+ a b c))  # => 6

(let
  [a 1
   b (+ a 1)
   c (+ b 1)]
  (+ a b c))  # => 6
letcellularmitosisPlayground
(reduce string "ha" ["ha" "ha" "ha" "ha"]) # => "hahahahaha"

(accumulate string "ha" ["ha" "ha" "ha" "ha"]) # => @["haha" "hahaha" "hahahaha" "hahahahaha"]
accumulatejgartePlayground
(def f (ev/spawn 4))
(ev/sleep 0.0001) # give ev a chance in the REPL, remove in file
(fiber/last-value f) # => 4
fiber/last-valuepepePlayground
(pairs {:a 1 :b 2 :c 3})
# =>
@[(:c 3) (:a 1) (:b 2)]
pairsuvtcPlayground
# foo.txt is a file with contents "hello\nworld\n".
(slurp "foo.txt")  # => @"hello\nworld\n"
(string/split "\n" (slurp "foo.txt"))  # => @["hello" "world" ""]

(defn slurp-lines [path]
  (string/split "\n" (slurp path)))

(slurp-lines "foo.txt")  # => @["hello" "world" ""]

(string/join @["hello" "world" ""] "\n")  # => "hello\nworld\n"
(spit "foo2.txt" (string/join @["hello" "world" ""] "\n"))
# The contents of foo.txt and foo2.txt are now identical.

(defn spit-lines [path lines]
  (spit path (string/join lines "\n")))

(spit-lines "foo3.txt" (slurp-lines "foo.txt"))
# The contents of foo.txt and foo3.txt are now identical.
spitcellularmitosisPlayground
# excess elements of the longer list are discarded
(interleave [1] 
            [2 4] 
            [3 6])
# -> @[1 2 3]
interleaveKrasjetPlayground
(map dictionary? [ 'ab   :ab   "ab"   @"ab"  [97 98]  @[97 98]  {0 97 1 98}  @{0 97 1 98}  ])
# =>            @[ false false false  false  false    false     true         true          ]

(map struct?     [ 'ab   :ab   "ab"   @"ab"  [97 98]  @[97 98]  {0 97 1 98}  @{0 97 1 98}  ])
# =>            @[ false false false  false  false    false     true         false         ]

(map table?      [ 'ab   :ab   "ab"   @"ab"  [97 98]  @[97 98]  {0 97 1 98}  @{0 97 1 98}  ])
# =>            @[ false false false  false  false    false     false        true          ]
struct?cellularmitosisPlayground
# Consider this problem: As a module author, I want to define a dynamic
# binding `:debug` to provide additional diagnostic information when an
# error occurs in a module function. I'll use `defdyn` to create a public
# alias for my dynamic binding:

# In the file: my-mod.janet
# The `defdyn` macro creates the dynamic binding :debug, and explicitly
# exposes it in the module's API as `my-mod/*debug*`.
(defdyn *debug*)

# contrived function - the important thing is that it enables additional
# diagnostic logging when the `*debug*` alias's reference dynamic binding
# is true.
(defn my-func [& params]
  (try
    (do
      (when (empty? params)
        (error "missing required argument")))
    ([err fib]
      (when (dyn *debug*)
        (print "[diagnostics] ..."))
      (error (string "error occurred: " err)))))

# Let's test our module from the REPL.

# $ repl:1:> (import /my-mod)
# $ repl:2:> (setdyn my-mod/*debug* true) # enable debug mode
# $ repl:3:> (my-mod/my-func)
# [diagnostics] ...
# error: error occured: missing required argument
#   in my-func [my-mod.janet] on line 11, column 7
#   in thunk [repl] (tail call) on line 4, column 1
# entering debug[1] - (quit) to exit
# debug[1]:1:>

# We see our diagnostic message, but we also entered Janet's built-in
# debugger! That's not what we intended. Why did this happen?

# It turns out that our module's `my-mod/*debug*` alias is namespaced, but the
# referenced `:debug` dynamic binding is not. We've created a collision with
# the `:debug` dynamic binding in the core API that activates the debugger
# on error.

# $ repl> *debug*
:debug
# $ repl> my-mod/*debug*
:debug

# The solution is to set the :defdyn-prefix dynamic binding to add a namespace
# for all dynamic bindings in our module. We should use a reasonably unique
# prefix - let's go with the name of the module's public git repo. It's okay
# for the prefix to be long - it will be used as the key for the dynamic
# binding in the current environment, but the user won't typically interact
# with it directly. The prefix is effectively "hidden" from the user. We'll
# prepend this line at the top of our module:
(setdyn *defdyn-prefix* "codeberg.org/quexxon/my-mod/")

# Now our `my-mod/*debug*` alias refers to an isolated, namespaced binding:
# $ repl:1:> (import /my-mod)
# $ repl:2:> my-mod/*debug*
:codeberg.org/quexxon/my-mod/debug
# $ repl:3:> (setdyn my-mod/*debug* true) # enable debug mode
# $ repl:4:> (my-mod/my-func)
# [diagnostics] ...
# error: error occured: missing required argument
#   in my-func [my-mod.janet] on line 11, column 7
#   in thunk [repl] (tail call) on line 4, column 1
# $ repl:5:>

# Much better! We see our diagnostic message, but we didn't trigger Janet's
# debugger. As a general rule, always set `*defdyn-prefix*` to a unique
# value when defining dynamic bindings for your module.
*defdyn-prefix*quexxonPlayground
(string/check-set "0123456789abcdef" "deadbeef") # => true
string/check-setsogaiuPlayground