As I've been playing around with L#, I ran across a few pretty
universally useful things that don't currently come bundled. So I
whipped up a basic library that contains a few useful things. I should
have a permanent home for this soon, but I don't at the moment, so I'm
just going to post it here for now.
I'm far from a Lisp expert, so if anyone wants to work out a better
implementation of some of this code, I'll be happy to include it in the
next version.
; basics.ls -- implements some universally used functions in
; the L# language
;
; Copyright (c) 2006, Andrew Norris
;
; This file doesn't contains anything especially remarkable,
; and anyone is free to reuse this in whatever fashion you
; like, and include it in a product licensed under any terms.
; Please retain the copyright attribution. Thanks.
; reasonably efficient list concatenation function
(= concat (fn (&rest items)
(let sb (new system.text.stringbuilder)
(foreach elem items
(call append sb elem))
(tostring sb ))))
; recovers the string value of an object for use in code
(= str (fn (obj)
(writetostring printer obj)))
; applies function f to a list of items and returns the
; result
(= map (fn (f lst)
(if (== (length lst) 1)
(list (f (car lst)))
(append (list (f (car lst))) (map f (cdr lst))))))
; returns the items in the list for which f(item) is true
(= filter (fn (f lst)
(let results nil
(each item lst
(when (f item)
(= results
(if (== results nil)
(list item)
(cons item results)))))
(if (!= results nil)
(= results (reverse results)))
results)))
; returns the result of applying a group function over
; the list lst
;
; for example, (reduce (fn (a b) (* a b)) '(2 3 4 5) 1)
; will initialize with the value 1, and return the
; product of all of the values of the list, i.e.
; 1 * 2 * 3 * 4 * 5 = 120
(= reduce (fn (f lst init)
(each item lst
(= init (f init item)))
init))
; pushes item on to the front of list lst, altering the
; actual list passed in
(defmacro push (lst item)
`(= ,lst (cons ,item ,lst)))
; pushes item on to list lst, altering the actual list
; passed in
; note: uses a goofy variable, because 1.2.1 doesn't have
; gensym
(defmacro pop (lst)
`(let obscure-item-name (car ,lst)
(= ,lst (cdr ,lst))
obscure-item-name)))
(defmacro leakypop (lst)
`(let leak (car ,lst) (= ,lst (cdr ,lst)) leak))
;; this works
(let mylist '(1 2 3 4 5) (prl (leakypop mylist) " " (leakypop mylist))
pass)
;; this doesn't
(let leak '(1 2 3 4 5) (prl (leakypop leak) " " (leakypop leak)) fail)
(= *gensymcount* 0)
;; we need a symbol, so use LSharp.Symbol.FromName(s)...
(= gensym (fn () (fromname symbol (format string "g:{0}"
(= *gensymcount* (++ *gensymcount*))))))
(defmacro pop (lst) (let noleak (gensym)
`(let ,noleak (car ,lst) (= ,lst (cdr ,lst)) ,noleak)))
(let noleak '(1 2 3 4 5) (prl (pop noleak) " " (pop noleak)))
One thing I've found missing was a way of getting stuff into a typed
array easily - it's a nuisance to call something like String.Split.
Ultimately, it'd be nice if you could use 'the' to get out an array
typed other than Object[], but until then, I've knocked up a function
that people might find useful:
(= make-array
(fn (typeobject elements)
(do
(= arrayobject (CreateInstance System.Array typeobject (length
elements)))
(to i (length elements) (SetValue arrayobject (nth i elements)
i))
arrayobject
)
)
)
You can then use it thus:
; Split on space, comma or semi-colon
(= string-to-split "One Two Three,Four;Five")
(= delimiters (make-array (typeof string) '(" " "," ";")))
(= split-result (split string-to-split delimiters (None
System.StringSplitOptions)))
(map (fn (x) (prl x)) split-result)
Any improvements people can suggest would be welcome.
Cheers,
Ian D