mirror of
https://github.com/janet-lang/janet
synced 2024-12-28 09:20:26 +00:00
Update Introduction.
parent
e8be15c43c
commit
6762f9cf87
112
Introduction.md
112
Introduction.md
@ -196,9 +196,16 @@ literals without binding them to a symbol.
|
|||||||
```
|
```
|
||||||
# Evaluates to 40
|
# Evaluates to 40
|
||||||
((fn [x y] (+ x x y)) 10 20)
|
((fn [x y] (+ x x y)) 10 20)
|
||||||
|
# Also evaluates to 40
|
||||||
|
((fn @[x y] (+ x x y)) 10 20)
|
||||||
|
|
||||||
|
# Will throw an error about the wrong arity
|
||||||
|
((fn [x] x) 1 2)
|
||||||
|
# Will not throw an error about the wrong arity
|
||||||
|
((fn @[x] x) 1 2)
|
||||||
```
|
```
|
||||||
|
|
||||||
The above expression first creates an anonymous function that adds twice
|
The first expression creates an anonymous function that adds twice
|
||||||
the first argument to the second, and then calls that function with arguments 10 and 20.
|
the first argument to the second, and then calls that function with arguments 10 and 20.
|
||||||
This will return (10 + 10 + 20) = 40.
|
This will return (10 + 10 + 20) = 40.
|
||||||
|
|
||||||
@ -206,6 +213,9 @@ There is a common macro `defn` that can be used for creating functions and immed
|
|||||||
them to a name. `defn` works as expected at both the top level and inside another form. There is also
|
them to a name. `defn` works as expected at both the top level and inside another form. There is also
|
||||||
the corresponding
|
the corresponding
|
||||||
|
|
||||||
|
Note that putting an ampersand in front of the argument list inhibits strict arity checking.
|
||||||
|
This means that such a function will accept fewer or more arguments than specified.
|
||||||
|
|
||||||
```lisp
|
```lisp
|
||||||
(defn myfun [x y]
|
(defn myfun [x y]
|
||||||
(+ x x y))
|
(+ x x y))
|
||||||
@ -365,6 +375,8 @@ itself, and the second parameter is the key.
|
|||||||
(get "hello, world" 0) # -> 104
|
(get "hello, world" 0) # -> 104
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Destructuring
|
||||||
|
|
||||||
In many cases, however, you do not need the `get` function at all. Janet supports destructuring, which
|
In many cases, however, you do not need the `get` function at all. Janet supports destructuring, which
|
||||||
means both the `def` and `var` special forms can extract values from inside structures themselves.
|
means both the `def` and `var` special forms can extract values from inside structures themselves.
|
||||||
|
|
||||||
@ -469,20 +481,110 @@ For any given function, use the `doc` macro to view the documentation for it in
|
|||||||
To see a list of all global functions in the repl, type the command
|
To see a list of all global functions in the repl, type the command
|
||||||
|
|
||||||
```lisp
|
```lisp
|
||||||
(getproto *env*)
|
(table.getproto *env*)
|
||||||
|
# Or
|
||||||
|
(all-symbols)
|
||||||
```
|
```
|
||||||
Which will print out every built-in global binding
|
Which will print out every built-in global binding
|
||||||
(it will not show your global bindings). To print all
|
(it will not show your global bindings). To print all
|
||||||
of your global bindings, just use *env*, which is a var
|
of your global bindings, just use \*env\*, which is a var
|
||||||
that is bound to the current environment.
|
that is bound to the current environment.
|
||||||
|
|
||||||
|
The convention of surrounding a symbol in stars is taken from lisp
|
||||||
|
and Clojure, and indicates a global dynamic variable rather than a normal
|
||||||
|
definition. To get the static environment at the time of compilation, use the
|
||||||
|
`_env` symbol.
|
||||||
|
|
||||||
# Prototypes
|
# Prototypes
|
||||||
|
|
||||||
:)
|
To support basic generic programming, Janet tables support a prototype
|
||||||
|
table. A prototype table contains default values for a table if certain keys
|
||||||
|
are not found in the original table. This allows many similar tables to share
|
||||||
|
contents without duplicating memory.
|
||||||
|
|
||||||
|
```lisp
|
||||||
|
# One of many Object Oriented schemes that can
|
||||||
|
# be implented in janet.
|
||||||
|
(def proto1 @{:type :my.custom1
|
||||||
|
:behave (fn [self x] (print "behaving " x))})
|
||||||
|
(def proto2 @{:type :my.custom2
|
||||||
|
:behave (fn [self x] (print "behaving 2 " x))})
|
||||||
|
|
||||||
|
(def thing1 (table.setproto @{} proto1))
|
||||||
|
(def thing2 (table.setproto @{} proto2))
|
||||||
|
|
||||||
|
(print (get thing1 :type)) # prints :my.custom1
|
||||||
|
(print (get thing2 :type)) # prints :my.custom2
|
||||||
|
|
||||||
|
(defn behave [x y]
|
||||||
|
(let [{:behave f} x]
|
||||||
|
(f x y)))
|
||||||
|
|
||||||
|
(behave thing1 :a) # prints "behaving :a"
|
||||||
|
(behave thing2 :b) # prints "behaving 2 :b"
|
||||||
|
```
|
||||||
|
|
||||||
|
Looking up in a table with a prototype can be summed up with the following algorithm.
|
||||||
|
|
||||||
|
1. `(get my-table my-key)` is called.
|
||||||
|
2. my-table is checked for the key if my-key. If there is a value for the key, it is returned.
|
||||||
|
3. if there is a prototype table for my-table, set `my-table = my-table's prototype` and got to 2.
|
||||||
|
4. Return nil as the key was not found.
|
||||||
|
|
||||||
|
Janet will check up to about a 1000 prototypes recursively by default before giving up and returning nil. This
|
||||||
|
is to prevent an infinite loop. This value can be changed by adjusting the `JANET_RECURSION_GUARD` value
|
||||||
|
in janet.h.
|
||||||
|
|
||||||
|
Note that Janet prototypes are not as expressive as metatables in Lua and many other languages.
|
||||||
|
This is by design, as adding Lua or Python like capabilities would not be technically difficult.
|
||||||
|
Users should prefer plain data and functions that operate on them rather than mutable objects
|
||||||
|
with methods.
|
||||||
|
|
||||||
# Fibers
|
# Fibers
|
||||||
|
|
||||||
:)
|
Janet has support for single-core asynchronous programming via coroutines, or fibers.
|
||||||
|
Fibers allow a process to stop and resume execution later, essentially enabling
|
||||||
|
multiple returns from a function. This allows many patterns such a schedules, generators,
|
||||||
|
iterators, live debugging, and robust error handling. Janet's error handling is actually built on
|
||||||
|
top of fibers (when an error is thrown, the parent fiber will handle the error).
|
||||||
|
|
||||||
|
A temporary return from a fiber is called a yield, and can be invoked with the `yield` function.
|
||||||
|
To resume a fiber that has been yielded, use the `resume` function. When resume is called on a fiber,
|
||||||
|
it will only return when that fiber either returns, yields, throws an error, or otherwise emits
|
||||||
|
a signal.
|
||||||
|
|
||||||
|
Different from traditional coroutines, Janet's fibers implement a signaling mechanism, which
|
||||||
|
is used to differentiate different kinds of returns. When a fiber yields or throws an error,
|
||||||
|
control is returned to the calling fiber. The parent fiber must then check what kind of state the
|
||||||
|
fiber is in to differentiate errors from return values from user defined signals.
|
||||||
|
|
||||||
|
To create a fiber, user the `fiber.new` function. The fiber constructor take one or two arguments.
|
||||||
|
the first, necessary argument is the function that the fiber will execute. This function must accept
|
||||||
|
an arity of one. The next optional argument is a collection of flags checking what kinds of
|
||||||
|
signals to trap and return via `resume`. This is useful so
|
||||||
|
the programmer does not need to handle all different kinds of signals from a fiber. Any untrapped signals
|
||||||
|
are simply propagated to the next fiber.
|
||||||
|
|
||||||
|
```lisp
|
||||||
|
(def f (fiber.new (fn @[]
|
||||||
|
(yield 1)
|
||||||
|
(yield 2)
|
||||||
|
(yield 3)
|
||||||
|
(yield 4)
|
||||||
|
5)))
|
||||||
|
|
||||||
|
# Get the status of the fiber (:alive, :dead, :debug, :new, :pending, or :user0-:user9)
|
||||||
|
(print (fiber.status f)) # -> :new
|
||||||
|
|
||||||
|
(print (resume f)) # -> prints 1
|
||||||
|
(print (resume f)) # -> prints 2
|
||||||
|
(print (resume f)) # -> prints 3
|
||||||
|
(print (resume f)) # -> prints 4
|
||||||
|
(print (fiber.status f)) # -> print :pending
|
||||||
|
(print (resume f)) # -> prints 5
|
||||||
|
(print (fiber.status f)) # -> print :dead
|
||||||
|
(print (resume f)) # -> throws an error because the fiber is dead
|
||||||
|
```
|
||||||
|
|
||||||
# Macros
|
# Macros
|
||||||
|
|
||||||
|
@ -190,7 +190,6 @@ failure to return or error.
|
|||||||
| `jmp` | `(jmp label)` | pc = label, pc += offset |
|
| `jmp` | `(jmp label)` | pc = label, pc += offset |
|
||||||
| `jmpif` | `(jmpif cond label)` | if $cond pc = label else pc++ |
|
| `jmpif` | `(jmpif cond label)` | if $cond pc = label else pc++ |
|
||||||
| `jmpno` | `(jmpno cond label)` | if $cond pc++ else pc = label |
|
| `jmpno` | `(jmpno cond label)` | if $cond pc++ else pc = label |
|
||||||
| `len` | `(len dest ds)` | $dest = length(ds) |
|
|
||||||
| `ldc` | `(ldc dest index)` | $dest = constants[index] |
|
| `ldc` | `(ldc dest index)` | $dest = constants[index] |
|
||||||
| `ldf` | `(ldf dest)` | $dest = false |
|
| `ldf` | `(ldf dest)` | $dest = false |
|
||||||
| `ldi` | `(ldi dest integer)` | $dest = integer |
|
| `ldi` | `(ldi dest integer)` | $dest = integer |
|
||||||
@ -198,6 +197,7 @@ failure to return or error.
|
|||||||
| `lds` | `(lds dest)` | $dest = current closure (self) |
|
| `lds` | `(lds dest)` | $dest = current closure (self) |
|
||||||
| `ldt` | `(ldt dest)` | $dest = true |
|
| `ldt` | `(ldt dest)` | $dest = true |
|
||||||
| `ldu` | `(ldu dest env index)` | $dest = envs[env][index] |
|
| `ldu` | `(ldu dest env index)` | $dest = envs[env][index] |
|
||||||
|
| `len` | `(len dest ds)` | $dest = length(ds) |
|
||||||
| `lt` | `(lt dest lhs rhs)` | $dest = $lhs < $rhs |
|
| `lt` | `(lt dest lhs rhs)` | $dest = $lhs < $rhs |
|
||||||
| `lti` | `(lti dest lhs rhs)` | $dest = $lhs \<i $rhs |
|
| `lti` | `(lti dest lhs rhs)` | $dest = $lhs \<i $rhs |
|
||||||
| `ltim` | `(ltim dest lhs im)` | $dest = $lhs \<i im |
|
| `ltim` | `(ltim dest lhs im)` | $dest = $lhs \<i im |
|
||||||
|
Loading…
Reference in New Issue
Block a user