TOC »
- Rationale
- API
- pl-parameter
- pl-checker
- pl-checker?
- pl
- pl?
- pl-maker
- pl-at
- pl-set!
- pl-length
- pl-null?
- pl-head
- pl-tail
- pl-data
- pl-cons
- pl-car
- pl-cdr
- pl-of?
- pl-iterate
- pl-drop
- pl-drop-while
- pl-take
- pl-take-while
- pl-reverse
- pl-map
- pl-for-each
- pl-memp
- pl-memq
- pl-memv
- pl-member
- pl-index
- pl-filter
- pl-append
- pl-fold-right
- pl-fold-right0
- pl-fold-left
- pl-fold-left0
- pl-adjoin
- pl-remove-dups
- pl-flat?
- pl-flatten
- pl-collect
- pseudolists
- Examples
- API
- Requirements
- Last update
- Author
- Repository
- License
- Version history
- Version History
Rationale
This module exports routines to handle pseudolists as a generalisation of ordinary lists. They can be considered as parametrized (or tagged) lists, where the parameter (or tag) is stored in the sentinel of a dotted list. In such a naive approch, we are faced with two problems.
First, since dotted lists differ from lists only insofor, as their sentinels might be arbitrary atoms instead of the empty list. In other words, a dotted list is either a pair or an atom. But since an atom is simply not a pair, everything is a pseudolist, in particular, a list is one. Hence, there is no meaningfull predicate for dotted lists.
Second, there is an efficency problem: to get a handle to the sentinel, we have to traverse the whole dotted list. This is not acceptable, if, for example, the parameter is a type predicate to check the type of items to be put into the dotted list. Ok, as in previous versions of this module, we can put the sentinel into a parameter, but this alone doesn't help much, if different parameters are used simultaneously.
This module offers a simple solution to both problems: Make the dotted list callable, in other words, put it into a closure and acces the items as well as the sentinel -- and the length for that matter -- via calls to that closure, e.g. (pls i), where i is an index.
Note, that most procedures are implemented in a curried and uncurried form, but only the latter is described in detail in the documentation. The former can be used in map and friends.
Note also, that the order or arguments of all procedures is consistent: The pseudolist argument(s) are always last, other procedures first.
API
pl-parameter
- pl-parameterparameter
- pl-parameter newparameter
returns or resets the sentinel of a pseudolist, initially '()
pl-checker
- pl-checker ok? argprocedure
- pl-checker ok?procedure
type constructor: wrap the predicate ok? into a unary procedure, which returns its argument unchanged, if only it passes the ok? test. An uncurried version is given as well
pl-checker?
- pl-checker? xprprocedure
type predicate. Used to check if the tag can be used to check all items.
pl
- pl #!rest argsprocedure
constructor: creates a pseudolist with sentinel tag from pl-parameter and items from args, encapsulated into a closure, which, when called with an index, returns the argument at that index, or, when called with -1, returns the length of args.
pl?
- pl? xprprocedure
type predicate
pl-maker
- pl-maker len fillprocedure
- pl-maker lenprocedure
creates a pseudolist of length len with sentinel (pl-parameter), items fill or (pl-sentinel), if fill is not given
pl-at
- pl-at k plsprocedure
- pl-at kprocedure
returns the kth item of pls
pl-set!
- pl-set! k val plsprocedure
sets the kth item of pls to val
pl-length
- pl-length plsprocedure
returns the length of the pseudolist pls
pl-null?
- pl-null? xprprocedure
checks, if no items are stored in the pseudolist xpr
pl-head
- pl-head plsprocedure
returns the list part of the pseudolist pls
pl-tail
- pl-tail plsprocedure
returns the sentinel of the pseudolist pls
pl-data
- pl-data plsprocedure
returns the dotted list underlying the pseudolist pls
pl-cons
- pl-cons x plsprocedure
- pl-cons xprocedure
adds the item x to the front of the pseudolist pls
pl-car
- pl-car plsprocedure
returns the first item of the pseudolist pls
pl-cdr
- pl-cdr plsprocedure
returns a new pseudolist removing the first item of pls
pl-of?
- pl-of? tag #!rest predsprocedure
creates a unary predicate, which tests, if its argument is a pseudolist with parameter tag, whose items pass all the predicates preds
pl-iterate
- pl-iterate fn times initprocedure
- pl-iterate fn timesprocedure
creates a pseudolist with sentinel (pl-parameter) applying fn to init recursively k times
pl-drop
- pl-drop n plsprocedure
- pl-drop nprocedure
returns a new pseudolist removing the first n items of the pseudolist pls
pl-drop-while
- pl-drop-while ok? plsprocedure
- pl-drop-while ok?procedure
returns the tail of pls starting with the first item that does not pass the ok? test
pl-take
- pl-take n plsprocedure
- pl-take nprocedure
returns a new pseudolist consisting of the first n items of the pseudolist pls, keeping the sentinel
pl-take-while
- pl-take-while ok? plsprocedure
- pl-take-while ok?procedure
returns the sublist of pls consisting of items until the first item doesn't pass the ok? test.
pl-reverse
- pl-reverse plprocedure
reverses its pseudolist argument to a new pseudolist with same sentinel
pl-map
- pl-map fn #!rest plssprocedure
maps fn over the pseudolists plss as long as none of the items is pl-null? and returns a new pseudolist if all sentinels are equal. Note, that this is R7RS-, not R5RS-logic.
pl-for-each
- pl-for-each fn pls #!rest plssprocedure
applies fn over the pseudolists (cons pls plss) stops if one of the items is pl-null? Note, that this is R7RS-, not R5RS-logic
pl-memp
- pl-memp ok? plsprocedure
- pl-memp ok?procedure
returns the subpseudolist starting at the first item which passes the ok? test, keeping ps's sentinel. Returns #f if no item passes the ok? test
pl-memq
- pl-memq x plsprocedure
- pl-memq xprocedure
same as (pl-memp (cut eq? <> x) pls)
pl-memv
- pl-memv x plsprocedure
- pl-memv xprocedure
same as (pl-memp (cut eqv? <> x) pls)
pl-member
- pl-member x plsprocedure
- pl-member xprocedure
same as (pl-memp (cut equal? <> x) pls)
pl-index
- pl-index ok? plsprocedure
- pl-index ok?procedure
returns the index of the first item passing the ok? test, -1 otherwise
pl-filter
- pl-filter ok? plsprocedure
- pl-filter ok?procedure
filters a pseudolist by means of a predicate ok? returning two new pseudolists, those of items of pls passing the ok? test, and those that don't
pl-append
- pl-append pls #!rest plssprocedure
appends all argument pseudolist, provided their tags are all equal
pl-fold-right
- pl-fold-right op init plsprocedure
- pl-fold-right op initprocedure
folds pls from the right with binary operation op and starting value init
pl-fold-right0
- pl-fold-right0 op plsprocedure
- pl-fold-right0 opprocedure
folds (pl-cdr pls) from the right with binary operation op and starting value (pl-car pls)
pl-fold-left
- pl-fold-left op init plsprocedure
- pl-fold-left op initprocedure
folds pls from the left with binary operation op and starting value init
pl-fold-left0
- pl-fold-left0 op plsprocedure
- pl-fold-left0 opprocedure
folds (pl-cdr pls) from the left with binary operation op and starting value (pl-car pls)
pl-adjoin
- pl-adjoin obj plsprocedure
- pl-adjoin objprocedure
add obj to the front of pls only if it is not already a member of pls
pl-remove-dups
- pl-remove-dups plsprocedure
removes the duplicates in the pseudolist pls
pl-flat?
- pl-flat? xprprocedure
is xpr a flat pseudolist, i.e. not containing other pseudolists
pl-flatten
- pl-flatten pl-treeprocedure
flattens the nested pseudolist pl-tree to a pseudolist, i.e. splices the pseudolist items of pl-tree into pl-tree provided all parameters are equal
pl-collect
- (pl-collect item-xpr (var pls ok-xpr ...) (var1 pls1 ok-xpr1 ...) ...)syntax
creates a new pseudolist by binding var to each element of the pseudolist pls in sequence, and if it passes the checks, ok-xpr ..., inserts the value of xpr into the resulting pseudolist. The qualifieres, (var pls ok-xpr ...), are processed sequentially from left to right, so that filters of a qualifier have access to the variables of qualifiers to its left.
pseudolists
- pseudolistsprocedure
- pseudolists symprocedure
with sym: documentation of exported symbol without sym: list of exported symbols
Examples
(import pseudolists) '(basic? parameter (pl-parameter 0) pls (pl 0 1 2 3) mls (pl-maker 5) ils (pl-iterate add1 5 1)) (pl-parameter) ;-> 0 (pl-data pls) ;-> (quote (0 1 2 3 . 0)) (pl-data mls) ;-> (quote (0 0 0 0 0 . 0)) (pl-data ils) ;-> (quote (1 2 3 4 5 . 0)) (pl? pls) ;-> #t (pl? mls) ;-> #t (pl? ils) ;-> #t (pl? '(0 1 2 3)) ;-> #f ((pl-of? 0) pls) ;-> #t ((pl-of? '()) mls) ;-> #f (pl-car mls) ;-> 0 (pl-at 3 mls) ;-> 0 (pl-at 3 pls) ;-> 3 (pls 3) ;-> 3 (pl-head pls) ;-> (quote (0 1 2 3)) (pls) ;-> (quote (0 1 2 3)) (pl-tail pls) ;-> 0 (pl-data pls) ;-> (quote (0 1 2 3 . 0)) (pl-data mls) ;-> (quote (0 0 0 0 0 . 0)) (pl-tail mls) ;-> 0 (pl-data ils) ;-> (quote (1 2 3 4 5 . 0)) (ils) ;-> (quote (1 2 3 4 5)) (pl-tail ils) ;-> 0 (pl-head (pl-cons -1 pls)) ;-> (quote (-1 0 1 2 3)) (pl-head (pl-cdr pls)) ;-> (quote (1 2 3)) (pl-set! 0 1 mls) ;-> (void) (pl-at 0 mls) ;-> 1 (pl-set! 1 2 mls) ;-> (void) (pl-at 1 mls) ;-> 2 (mls 1) ;-> 2 (mls 2 3) ;-> (void) (mls 2) ;-> 3 (mls) ;-> (quote (1 2 3 0 0)) (pl-head mls) ;-> (quote (1 2 3 0 0)) (newline) '(checked? parameter (pl-parameter (pl-checker integer?)) pls (pl 0 1 2 3)) (pl-tail pls) ;-> (pl-parameter) (pl-head pls) ;-> (quote (0 1 2 3)) (condition-case (pl 0 1 #f 3) ((exn) #f)) ;-> #f (condition-case (pl-set! 0 #f pls) ((exn) #f)) ;-> #f (pl-set! 0 100 pls) ;-> (void) (pl-car pls) ;-> 100 (pls 0 10) ;-> (void) (pls 0) ;-> 10 (newline) '(ops? parameter (pl-parameter 0) pls (pl 0 1 2 3) mls (pl-maker 5) ils (pl-iterate add1 5 1) ii (pl-iterate add1 5)) (pl-parameter) ;-> 0 (pl-data pls) ;-> (quote (0 1 2 3 . 0)) (pl-data mls) ;-> (quote (0 0 0 0 0 . 0)) (pl-data ils) ;-> (quote (1 2 3 4 5 . 0)) (pl-data (ii 1)) ;-> (quote (1 2 3 4 5 . 0)) (pls) ;-> (quote (0 1 2 3)) (pl? pls) ;-> #t ((pl-of? 1) pls) ;-> #f ((pl-of? 0) pls) ;-> #t ((pl-of? 0 integer?) pls) ;-> #t ((pl-of? 0 integer? positive?) pls) ;-> #f (pl? '(0 1 2 3 . 0)) ;-> #f (pl-at 0 pls) ;-> 0 (pl-at 3 pls) ;-> 3 (pl-head (pl-map add1 pls)) ;-> (quote (1 2 3 4)) (pl-head (pl-map + pls pls)) ;-> (quote (0 2 4 6)) (pl-index negative? pls) ;-> -1 (pl-index odd? pls) ;-> 1 (pl-head (pl-filter odd? pls)) ;-> (quote (1 3)) (receive (_ pl-no) (pl-filter odd? pls) (pl-head pl-no)) ;-> (quote (0 2)) (pl-head (pl-append pls ils)) ;-> (quote (0 1 2 3 1 2 3 4 5)) (pl-head (pl-append pls ils mls)) ;-> (quote (0 1 2 3 1 2 3 4 5 0 0 0 0 0)) (pl-set! 2 20 pls) ;-> (void) (pl-head pls) ;-> (quote (0 1 20 3)) (pl-length pls) ;-> 4 (pl-tail pls) ;-> 0 (pl-at 2 pls) ;-> 20 (pl-head pls) ;-> (quote (0 1 20 3)) (pl-head (pl-drop 3 pls)) ;-> (quote (3)) (pl-head (pl-drop-while zero? pls)) ;-> (quote (1 20 3)) (pl-head (pl-drop-while (cut <= <> 10) pls)) ;-> (quote (20 3)) (pl-head (pl-take 3 pls)) ;-> (quote (0 1 20)) (pl-head (pl-take-while (cut <= <> 10) pls)) ;-> (quote (0 1)) (pl-head (pl-reverse pls)) ;-> (quote (3 20 1 0)) (pl-head (pl-memp (lambda (x) (> x 10)) pls)) ;-> (quote (20 3)) (pl-head mls) ;-> (quote (0 0 0 0 0)) ((pl-of? 0 zero?) mls) ;-> #t (pl-length mls) ;-> 5 (pl-set! 2 20 mls) ;-> (void) (pl-head mls) ;-> (quote (0 0 20 0 0)) (pl-tail mls) ;-> 0 (pl? mls) ;-> #t (pl-head (pl-maker 5 1)) ;-> (quote (1 1 1 1 1)) (pl? ils) ;-> #t (pl-head ils) ;-> (quote (1 2 3 4 5)) (pl-tail ils) ;-> 0 (pl-at 2 ils) ;-> 3 (pl? ii) ;-> #f (pl? (ii 1)) ;-> #t (pl-length (ii 1)) ;-> 5 (pl-at 3 (ii 1)) ;-> 4 (pl-head (pl-map * (pl 0 1 2 3) (pl 10 20))) ;-> (quote (0 20)) (condition-case (pl-map + (parameterize ((pl-parameter #f)) (pl 0 1 2 3)) (parameterize ((pl-parameter #t)) (pl 0 1 2 3))) ((exn) #f)) ;-> #f (newline) '(new-ops? parameter (pl-parameter 0) pls (pl 0 1 2 3 4 5)) (pl-data pls) ;-> (quote (0 1 2 3 4 5 . 0)) (pl-fold-right + 0 pls) ;-> 15 (pl-fold-left + 0 pls) ;-> 15 (pl-fold-right0 + pls) ;-> 15 (pl-fold-left0 + pls) ;-> 15 (pl-head (pl-fold-right pl-cons (pl) pls)) ;-> (quote (0 1 2 3 4 5)) (pl-fold-right cons '() pls) ;-> (quote (0 1 2 3 4 5)) (pl-head (pl-adjoin 3 pls)) ;-> (quote (0 1 2 3 4 5)) (pl-head (pl-adjoin #f pls)) ;-> (quote (#f 0 1 2 3 4 5)) (pl-head (pl-remove-dups pls)) ;-> (quote (0 1 2 3 4 5)) (pl-head (pl-remove-dups (pl 0 1 0 1 0 1))) ;-> (quote (0 1)) (pl-flat? pls) ;-> #t (pl-flat? (pl 0 (pl 1 (pl 2)))) ;-> #f (pl-head (pl-flatten (pl 1 2 3))) ;-> (quote (1 2 3)) (pl-head (pl-flatten (pl 1 '(2 3)))) ;-> (quote (1 (2 3))) (pl-head (pl-flatten (pl 1 (pl 2 3)))) ;-> (quote (1 2 3)) (pl-head (pl-flatten (pl 1 (pl 2 3) (pl 4 5) 6))) ;-> (quote (1 2 3 4 5 6)) (pl-head (pl-flatten (pl 1 (pl 2 (pl 3))))) ;-> (quote (1 2 3)) (pl-head (pl-flatten (pl 1 (pl 2 (pl 3 (pl 4)) 5) 6))) ;-> (quote (1 2 3 4 5 6)) (condition-case (pl-flatten (pl 1 (parameterize ((pl-parameter #f)) (pl 2 3)))) ((exn) #f)) ;-> #f (newline) (pl-data (pl-collect (add1 x) (x (pl 0 1 2 3)))) ;-> (quote (1 2 3 4 . 0)) (pl-data (pl-collect (add1 x) (x (pl 0 1 2 3)))) ;-> (quote (1 2 3 4 . 0)) (pl-data (pl-collect x (x (pl 0 1 2 3 4 5) (odd? x)))) ;-> (quote (1 3 5 . 0)) (pl-data (pl-collect x (x (pl 0 1 2 3 4 5) (odd? x)))) ;-> (quote (1 3 5 . 0)) (pl-data (pl-collect (* 10 n) (n (pl 0 1 2 3 4 5) (positive? n) (even? n)))) ;-> (quote (20 40 . 0)) (pl-data (pl-collect (list c k) (c (pl 'A 'B 'C)) (k (pl 1 2 3 4)))) ;-> (quote ((A 1) (A 2) (A 3) (A 4) (B 1) (B 2) (B 3) (B 4) (C 1) (C 2) (C 3) (C 4) . 0)) (newline)
Requirements
None
Last update
Feb 15, 2021
Author
Juergen Lorenz
Repository
This egg is hosted on the CHICKEN Subversion repository:
https://anonymous@code.call-cc.org/svn/chicken-eggs/release/5/pseudolists
If you want to check out the source code repository of this egg and you are not familiar with Subversion, see this page.
License
Copyright (c) 2013-2021 , Juergen Lorenz, ju (at) jugilo (dot) de All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Version history
Version History
- 3.0
- pseudolists as parametrized (or tagged) lists
- 2.0
- sentinels kept, not stripped
- 1.4
- pl-maker added
- 1.3
- sentinel-options removed, all constructors create ordinary lists
- 1.2
- macro pl-for renamed pl-collect
- 1.1
- some sentinel-option arguments added; syntax-change of pl-for and pl-iterate
- 1.0
- initial import