util.lsp

Module index



Module: util

Author: Jeff Ober
Version: 2.0
Original location: http://static.artfulcode.net/newlisp/util.lsp
Source: util.lsp
Package definition: util.qwerty

Various functions that the other libraries depend on (updated for newlisp 10).

Various helpful utilities for newLISP. Requires newlisp 10+.

Version history

2.1 • added with-open-device, partial • added make-array, array-iter and array-map

2.0 • updated for newlisp 10 (backwards-incompatible) • refactored assoc? (now permits any key that satisfies atom?) • get-assoc is now a regular function whose arguments must be quoted • slot functions removed as new association list features make them redundant • dict-keys refactored and renamed to keys • refactored dokeys for a slight speed improvement

1.4 • added slot-valuewith-slots now supports string keys • fixed bug when calling with-slots from within a context • with-slots now permits renaming of variables in binding to avoid clashes in nested calls • added get-assoc • added dict-keys • added dokeys

1.3with-slots now supports assoc data in the format (key val-1 val-2 ...) and '(key val)

1.2 • fixed bug that caused with-slots to return only the first value of a list

1.1 • added fmap, with-slots, and add-assoc

1.0 • initial release

- § -

type-of

syntax: (type-of object)
parameter: object - any object

type-of introspects the type of the passed argument, object, and returns a string representation of its type. Correctly identifies FOOP types as well, returning the string value of the first argument (by calling name on the context of the list).

example:
 (type-of 10) => "integer"
 (type-of "hello world") => "string"
 (type-of true) => "boolean"
 (type-of '(1 2 3)) => "list"
 (type-of (fn (x) (+ x x))) => "lambda"


- § -

gensym

syntax: (gensym [ctx])
parameter: ctx - optional; the context in which to create the symbol (default: MAIN)

Returns a symbol unique to the context passed. If ctx is nil, the symbol is created in MAIN. There is a hard limit on the number of possible symbols generated based on the max integer value of the system. Since newLISP wraps into negative numbers when passing the max value, the effective max value is twice the systems maximum integer value.

example:
 (gensym) => gensym-1
 (gensym) => gensym-2
 
 (define foo:foo)
 (gensym foo) => foo:gensym-1
 (gensym foo) => foo:gensym-2


- § -

assoc?

syntax: (assoc? expr)
parameter: expr - expression to be tested as an association list

Predicates that expr is an association list with a structure of '((key val) (key val) ...). To evaluate true key may have only one value, and keys must be symbols or strings. Only the first level is tested for associativity.

example:
 (assoc? '(1 2 3 4))
 => nil
 (assoc? '((a 1) (b 2) (c 3)))
 => true
 (assoc? '((a 1) (b 2) (c (1 2 3 4))))
 => true


- § -

get-assoc

syntax: (get-assoc expr)
parameter: expr - association indexing of (assoc-list key-1 [key-2 ...])

Extracts the value of the association expression. Expressions are in the same format as with the assoc function, but the result is the same as the lookup function, except the multiple values are returned correctly.

example:
 (set 'data '((name "Joe") (friends "John" "Steve")))
 (get-assoc (data 'name))
 => "Joe"
 (get-assoc (data 'friends))
 => '("John" "Steve")


- § -

fmap

syntax: (fmap sym-fun inst lst*)
parameter: sym-fun - quoted symbol naming a context function
parameter: inst - a FOOP instance
parameter: lst* - one or more lists

FOOP methods cannot be easily mapped, since map would require that the function be passed as context:function, curried for the intended FOOP instance. However, currying truncates a function's lambda list to two parameters, the first being the second argument to curry.

fmap solves this, although not extremely efficiently, with a lambda that wraps the context function.

example:
 (define (Foo:Foo) (list (context)))
 (define (Foo:make-list inst a b) (list a b)) ; pairs two elements
 
 (let ((a '(1 2 3)) (b '(4 5 6)) (inst (Foo)))
   (fmap 'Foo:make-list inst a b))
 
 => ((1 4) (2 5) (3 6))


- § -

keys

syntax: (keys context-dict)
parameter: context-dict - context dictionary

Returns a list of keys in the dictionary context-dict.

example:
 (define dict:dict)
 (dict "x" 10)
 (dict "y" 20)
 (keys dict)
 => '("x" "y")


- § -

dokeys

syntax: (dokeys (var dict) body)
parameter: var - variable to which the key name will be bound
parameter: dict - dictionary from which the keys will be extracted
parameter: body - the body forms to be executed with var bound to dict's keys

Evaluates body in a local block in which var is sequentially bound to each of dict's keys. Note that there is no special ordering of the keys.

example:
 (define dict:dict)
 (dict "x" 10)
 (dict "y" 20)
 (dokeys (key dict)
   (println key ": " (dict key)))
 => x: 10
 => y: 20


- § -

make-array

syntax: (make-array int-size fn-init)
parameter: int-size - the size of the new array
parameter: pass-index - when true (nil by default), passes the position index to fn-init

Generates a new one-dimensional array of size int-size and initializes each array index by repeatedly calling fn-init. The current index is available in $idx.

example:
 (setf arr (make-array 4 (gensym)))
 => '(gensym-1 gensym-2 gensym-3 gensym-4)


- § -

array-iter

syntax: (array-iter fn-func array-arr)
parameter: fn-func - a function to call on each index of the array
parameter: array-arr - an array

Calls fn-func on each index of array-arry. Returns the value of the last iteration. The current index is available in $idx.

example:
 (setf arr (array 4 (sequence 0 4))) ; => (0 1 2 3)
 (array-iter (fn (i) (println (+ i $idx))) arr)
 0
 2
 4
 6


- § -

array-map

syntax: (array-map fn-func array-arr) !
parameter: fn-func - a function to call on each index of the array
parameter: array-arr - an array

Similar to the built-in function map, array-map applies fn-func to each index of array-arr. array-map modifies array-arr in place.

example:
 (setf arr (array 10 (sequence 0 10))) ; => (0 1 2 3 4 5 6 7 8 9)
 (array-map (fn (i) (+ i $idx)))
 (println arr) ; => '(0 2 4 6 8 10 12 14 16 18)


- § -

with-open-device

syntax: (with-open-device descriptor [body-expressions])
parameter: descriptor - an open file descriptor
parameter: body-expressions - any number of expressions

Evaluates body-expressions with descriptor as the default device. Catches errors during evaluation and closes descriptor once complete, restoring the previous default device.

example:
 ; read one line from file and close
 (with-open-device (open "somefile.txt")
   (println (read-line)))


- § -

partial

syntax: (partial func expr)
parameter: func - a function to be partially applied
parameter: expr - an expression to replace the first argument of func

Returns a new function that has been partially applied to expr. Unlike curry, partial evaluates its arguments and does no damage to the parameter list of the resulting function, which continues to accept the rest of the parameters it would typically accept. This is particularly useful to fudge closures over FOOP methods by partially applying them to their instances. Note that macros and functions that do not evaluate their arguments may not be partially applied, due to the use of the apply function in this implementation.

example:
 (define (foo a b c)
   (join (list "foo" a b c) "|"))
 (setf foobar (partial foo "bar"))
 (foobar "baz" "bat") ; => "foo|bar|baz|bat"

- ∂ -

Artful Code

generated with newLISP  and newLISPdoc