Skip to content

Latest commit

 

History

History
1565 lines (981 loc) · 15.9 KB

dynref.md

File metadata and controls

1565 lines (981 loc) · 15.9 KB

LispBM library of dynamically loadable functionality

With LispBM comes a small library of dynamically loadable functions and macros. These functions occupy flash memory (if on an embedded platform) but only use heap if they are actually used by the application. Providing dynamically loadable operations is a way to save space while offering more sweet functionality.

LispBM can be built with varying amount of included dynamic loadable functionality. It is up to the LispBM integrator to decide what is included. As an integrator you can also decide to roll your entirely own set of dynamically loadable operations.

The inclusion of dynamically loadable functionality from this library is determined when LispBM is compiled using the following flags:

  • LBM_USE_DYN_FUNS : Add a library of functions to the dynamic loader.
  • LBM_USE_DYN_MACROS : Add a library of macros to the dynamic loader.
  • LBM_USE_DYN_DEFSTRUCT : Add the defstruct mechanism, requires LBM_USE_DYN_FUNS and LBM_USE_DYN_MACROS.
  • LBM_USE_DYN_LOOPS : Add loop macros, requires LBM_USE_DYN_MACROS.
  • LBM_USE_DYN_ARRAYS : Add functions on arrays. Requires LBM_USE_DYN_MACROS and LBM_USE_DYN_LOOPS.

The flags should be given to the compiler as -Dx for example -DLBM_USE_DYN_FUNS.

functions


abs

Compute the absolute value

Example Result
(abs -1)
1
(abs -1.000000f32)
1.000000f32
(abs 1)
1
(abs 1.000000f32)
1.000000f32
(abs (sin -3.140000f32))
0.001593f32

apply

Apply a function taking n arguments to a list of n elements

Example Result
(apply + (list 1 2 3))
6

filter

Filter a list from unwanted elements as decided by a predicate

Example Result
(define even (lambda (x) (= (mod x 2) 0)))
(closure (x) (= (mod x 2) 0) nil)
(filter even (list 1 2 3 4 5 6 7 8 9))
(2 4 6 8)

foldl

foldl walks through a list, left to right, while accumulating a result from applying a function to the element at hand and the result of its previous step. foldl takes an initial value used as the that is combined with the leftmost value of the list in the first iteration.

Example Result
(foldl + 0 (list 1 2 3 4 5 6 7 8 9 10))
55

foldl has an advantage over foldr in that it is implemented in a tail-recursive and constant-storage way.

Funnily enough, foldl using function cons and initial value nil converts a list to a snoc-list.

Example Result
(foldl cons nil (list 1 2 3 4 5 6 7 8 9 10))
((((((((((nil . 1) . 2) . 3) . 4) . 5) . 6) . 7) . 8) . 9) . 10)

Now we are going off on a tangent, but car and cdr switches roles with each other when operating on a snoc-list.

Example Result
(define my-snoc-list (foldl cons nil (list 1 2 3 4 5 6 7 8 9 10)))
((((((((((nil . 1) . 2) . 3) . 4) . 5) . 6) . 7) . 8) . 9) . 10)
(cdr my-snoc-list)
10
(car my-snoc-list)
(((((((((nil . 1) . 2) . 3) . 4) . 5) . 6) . 7) . 8) . 9)

foldr

foldr walks through a list, right to left, while combining value and prev result step by step. An initial value is provided and here used in the first, rightmost, operation.

foldr has a disadvantage compared to foldl as I don't think it is possible to give foldr a constant-space and tail-recursive implementation. One can make foldr tail-recursive by writing it in continuation passing style (CPS). The CPS version of foldr will run without building upon the return stack, but instead it will construct and expand upon a continuation object each iteration. This continuation object will grow at the same rate as the call-stack otherwise would but it would grow in heap usage.

Example Result
(foldr + 0 (list 1 2 3 4 5 6 7 8 9 10))
55

Much less amusingly compared to foldl, foldr of cons with initial value nil is the identity function on proper lists.

Example Result
(foldr cons nil (list 1 2 3 4 5 6 7 8 9 10))
(1 2 3 4 5 6 7 8 9 10)

iota

iota takes one number as argument and generates a list of values up to (not including) the given number.

Example Result
(iota 4)
(0 1 2 3)

second

second extracts the second element from a list.

Example Result
(second (list 1 2 3 4))
2
(second (list 1))
nil

str-cmp-asc

compare strings according to alphabetical order ascending.

Example Result
(str-cmp-asc "apa" "bepa")
t
(str-cmp-asc "bepa" "apa")
nil

str-cmp-dsc

compare strings according to alphabetical order descending.

Example Result
(str-cmp-dsc "apa" "bepa")
nil
(str-cmp-dsc "bepa" "apa")
t

str-merge

str-merge is an alternative name for the str-join operations. It is kept around for backwards compatibility.

Example Result
(str-merge "Kurt" " " "Russel")
Kurt Russel

third

third extracts the third element from a list.

Example Result
(third (list 1 2 3 4))
3
(third (list 1))
nil

macros


defun

defun is a macro that provides a shorthand form for defining a named function. (defun name args body) is expanded into (define name (lambda args body)).

Example Result
(defun f (x) (+ x 1))
(closure (x) (+ x 1) nil)
(f 1)
2

defunret

defunret is like defun but you are allowed to return at any point in the function body.

Example Result
(defunret g (x) (progn 
    1
    2
    (return 55)
    3
    4
    x))
(closure (x) (call-cc-unsafe (lambda (return) (progn 1 2 (return 55) 3 4 x))) nil)
(g 10)
55

defmacro

defmacro is a macro that provides a shorthand form for defining macros. (defmacro name args body) expands into (define name (macro args body)).

Example Result
(defmacro my-macro (a) `(list 'apa ,a))
(macro (a) (append (quote (list)) (list (quote (quote apa))) (list a)))
(my-macro 10)
(apa 10)

loop macros


loopfor

loopfor has the form (loopfor it start cond update body) and implements a for loop as familiar from for example C.

it is the iterator, start is what it is initialized to, cond is the condition that has the be true for the loop to continue running, update is how to update the iterator after each iteration and body is the code to execute each iteration. The iterator can be accessed from within body.

Example Result
 (define r 0)
 (loopfor i 0 (< i 5) (+ i 1)
      (setq r (+ r i)))
 r
10

loopwhile

loopwhile has the form (loopwhile cond body) and implements a while loop as familiar from for example C.

cond is the condition that has the be true for the loop to continue running and body is the code to execute each iteration.

Example Result
 (define a 0)
 (loopwhile (< a 10)
      (setq a (+ a 1)))
 a
10

looprange

looprange has the form (looprange it start end body) and implements a loop over a range similar to python's for i in range(n).

Iterate it from start to end and evaluate body for each iteration. The iterator it can be accessed from within body.

Example Result
 (define b 0)
 (looprange i 0 11 (setq b (+ b i)))
 b
55
Example Result
 (define my-ls nil)
 (looprange i 0 5 (setq my-ls (cons i my-ls)))
 my-ls
(4 3 2 1 0)

loopforeach

loopforeach has the form (loopforeach it lst body) and implements a loop over the elements of a list similar to python's for e in ....

Iterate over every element in the list lst and evaluate body for each iteration. The iterator it can be accessed from within body.

Example Result
 (define m 0)
 (loopforeach e (list 2 4 6 8) (setq m (+ m e)))
 m
20

loopwhile-thd

loopwhile-thd is like loopwhile but the thread runs in its own thread asynchronously. The form of a loopwhile-thd is (loopwhile-thd stack cond body).

A While-loop that starts in a new thread. The argument stack is the stack-size of the thread, cond is the condition that has the be true for the loop to continue running and body is the code to execute each iteration. The difference from the regular loopwhile is that the evaluator will continue running the code after this one before this one finishes, as this loop is evaluated in a new thread.

The following examples assumes that your LispBM integration has a way to print.

Example that forever prints "Hello World" every two seconds:

 (loopwhile-thd 100 t { 
    (print "Hello World") 
    (sleep 2) 
 })

The above is equivalent to the following code

(spawn 100 (fn () (loopwhile t {
                 (print "Hello World")
                 (sleep 2)
})))

It is possible to give the thread a name and/or a stack size. That gives the following combinations of possibilities:

No name and default stack size

(loopwhile-thd () t {
        (print "Hello World1")
        (sleep 2)
})

No name and stack size 100

(loopwhile-thd 100 t {
        (print "Hello World2")
        (sleep 2)
})

Name ThdTest and default stack size

(loopwhile-thd "ThdTest" t {
        (print "Hello World3"
)         (sleep 2)
})

Name ThdTest2 and stack size 100

(loopwhile-thd ("ThdTest2" 100) t {
        (print "Hello World4")
        (sleep 2)
})

Array functions


list-to-array

Convert a list to an array

Example Result
(list-to-array (list 1 2 3))
[|1 2 3|]
(list-to-array '(nil nil nil))
[|nil nil nil|]

array-to-list

Convert an array to a list

Example Result
(array-to-list (list-to-array (list 1 2 3)))
(1 2 3)
(array-to-list [|1 2 3 4|])
(1 2 3 4)

array?

Array predicate is true for arrays.

Example Result
(array? [|1 2 3|])
t
(array? 1)
nil
(array? 'apa)
nil
(array? (list 1 2 3))
nil

defstruct and its operations


defstruct defines a datastructure with named fields similar to a struct in C. defstruct takes two arguments, a struct name and a list of fields (defstruct name list-of-fields).

Structs are implemented as arrays of lisp values and offer constant time lookup of each of its fields. The struct itself does not occupy heap cells, but the values stored in the fields may.

As structs are allocated from array memory (lbm_memory), there is a potential for causing memory fragmentation.

The example below creates a structure type called my-struct with three fields called a, b and c.

Example Result
(defstruct my-struct (a b c))
t

Now instances of my-struct can be creted using make-my-struct.

Example Result
(define s1 (make-my-struct))
[|my-struct nil nil nil|]

when a struct is defined using defstruct a number of functions for manipulation of that kind of struct is automatically generated.

  • make-name : function for creation of struct with name name.
  • name? : predicate that is true for instances of the struct named name.
  • name-x : setter/getter for struct name and field x.

This will be more clear by showing with my-struct as example.

Example Result
(my-struct? s1)
t
(my-struct? "hej")
nil
(my-struct? 10)
nil

my-struct? is a predicate that is true for instances of my.struct.

Example Result
(my-struct-a s1 10)
[|my-struct 10 nil nil|]
(my-struct-b s1 20)
[|my-struct 10 20 nil|]
(my-struct-c s1 30)
[|my-struct 10 20 30|]

my-struct-x with 2 arguments is a setter. with just the struct instance as argument it is a getter.

Example Result
(my-struct-a s1)
10
(my-struct-b s1)
20
(my-struct-c s1)
30

This document was generated by LispBM version 0.30.3