Skip to content

Commit

Permalink
Merge pull request mighty-gerbils#562 from fare-patches/misc
Browse files Browse the repository at this point in the history
Misc
  • Loading branch information
fare authored Aug 2, 2020
2 parents 98d270b + 810b911 commit 3f248e1
Show file tree
Hide file tree
Showing 13 changed files with 413 additions and 64 deletions.
235 changes: 216 additions & 19 deletions doc/reference/misc.md
Original file line number Diff line number Diff line change
Expand Up @@ -1666,11 +1666,15 @@ or a weak hash-table, or one that is already populated for other reasons.

### invert-hash<-vector
``` scheme
(invert-hash<-vector vector to: (to (hash))) -> hash
(invert-hash<-vector vector
start: (start 0) end: (end (vector-length from))
to: (to (make-hash-table)) key: (key identity))
-> hash
```

Returns the inverse of a *vector*:
a hash-table *hash* whose keys are the values of those of *vector*,
Returns the inverse of the section of a *vector* in the given range from *start* included to *end* excluded,
a hash-table *hash* whose keys are extracted from values of those of *vector* by the function *key*
(that defaults to *identity*, i.e. the value itself is the key),
each mapped to one value that is an index that *vector* associates to the value.
If the index is unique, it will be used; if it isn't, any single of those indexes may be used.

Expand All @@ -1681,20 +1685,26 @@ or a weak hash-table, or one that is already populated for other reasons.

### invert-hash<-vector/fold
``` scheme
(invert-hash/fold vector to: (to (hash)) nil: (nil '()) cons: (cons cons)) -> hash-1
(invert-hash<-vector/fold
from start: (start 0) end: (end (vector-length from))
to: (to (make-hash-table)) nil: (nil '()) cons: (cons cons) key: (key identity)) -> to
```

Returns the inverse of a *vector*:
a hash-table *hash* whose keys are the values of those of *vector*,
each mapped to one value that is fold of all indexes that *vector* associates to the value.
By default, the fold consists in consing those keys into a list, in an unspecified order.
It could instead create a hash-table of those keys, or a sorted list or tree of them, etc.

Returns the inverse of the section of a *vector* in the given range from *start* included to *end* excluded,
a hash-table *hash* whose keys are extracted from values of those of *vector* by the function *key*
(that defaults to *identity*, i.e. the value itself is the key),
each mapped to one value that is an index that *vector* associates to the value.
Each time an index is found for a given key, it is combined together with previous indexes found
using the function *cons* (which defaults to actual `cons`),
with the value *nil* (which defaults to empty list `()`) being assumed as the initial value
before any index is found.
If an existing hash-table is passed as a *to* argument, it will be used as hash-table populated
with those inverse indexes, instead of a new equal-hash-table.
This feature can notably be used to provide a hash-table with different equality predicate,
or a weak hash-table, or one that is already populated for other reasons.



### hash-restrict-keys
``` scheme
(hash-restrict-keys hash key-list) -> hash-1
Expand All @@ -1713,6 +1723,26 @@ if it is not present, it is ignored.
Return a new hash-table that has the same keys as the original *hash*,
but whose values have been transformed by calling the function *fun*.

### hash-key-value-map
``` scheme
(hash-key-value-map fun from (to (hash)) -> to
```
Modifies the *to* hash-table (by default, a new `equal?` hash-table),
by calling a function *fun* on each key value pair of hash-table *from*
(passed as two arguments *key* and *value*), which must return either `#f` or a cons pair `(k1 . v1)`
that will be added to the destination hash-table *to*.
If a key *k1* appears multiple times, it is not guaranteed which will present in the end,
only that one of them will.

::: tip Examples:
```scheme
> (hash->list/sort
(hash-key-value-map
(lambda (k v) (and (even? v) (cons (/ v 2) (string-append k k))))
(hash ("a" 1) ("b" 2) ("c" 3) ("d" 4) ("e" 5) ("f" 6))) <)
((1 . "bb") (2 . "dd") (3 . "ff"))
```

### hash-filter
```scheme
(hash-filter hash pred (to (hash))) -> hash-1
Expand Down Expand Up @@ -1795,6 +1825,60 @@ Similar to `hash->list` and `table->list`,
this function returns a list of the key-value pairs in the *hash* table,
but also sorts this list by keys according to the provided predicate *pred*.

::: tip Examples:
``` scheme
> (hash->list/sort (hash (3 "c") (4 "d") (1 "a") (2 "b")) <)
((1 . "a") (2 . "b") (3 . "c") (4 . "d"))
```

### hash-get-set!
``` scheme
(hash-get-set! h k v) -> (void)
```

*hash-get-set!* is a synonym for *hash-put!* that makes it possible to
`(set! (hash-get h k) v)`.

::: tip Examples:
``` scheme
> (def h (hash))
> (hash-get-set! h 2 "b")
> (hash-get h 2)
"b"
> (set! (hash-get h 2) "B")
> (hash-get h 2)
"B"
```

### hash-ref-set!
``` scheme
(hash-ref-set! h k v) -> (void)
(hash-ref-set! h k d v) -> (void)
```

*hash-ref-set!* is a variant of *hash-put!* that makes it possible to
`(set! (hash-ref h k) v)` or `(set! (hash-get h k default) v)`.

::: tip Examples:
``` scheme
> (def h (hash))
> (hash-ref-set! h "a" 1)
> (hash-get h "a")
1
> (set! (hash-ref h "b") 2)
> (hash-get h "b")
2
> (defrules post-increment! () ((p x) (p x 1)) ((p x y ...) (begin0 x (set! x (+ x y ...)))))
> (post-increment! (hash-ref h "a") 10)
1
> (post-increment! (hash-ref h "a" 0))
11
> (post-increment! (hash-ref h "c" 0))
0
> (post-increment! (hash-ref h "c" 0))
1
```

## List utilities
::: tip To use the bindings from this module:
``` scheme
Expand Down Expand Up @@ -2094,6 +2178,33 @@ error ; uses set! internally, requires valid binding
```
:::

### pop!
``` scheme
(pop! lst) -> #f | elem
elem := first element from lst
lst := list, from which the first element will be removed
```

Macro that checks whether the *lst* is a cons cell, if so returns the car of that cons cell,
and sets *lst* to the cdr of that cons cell, otherwise returns `#f`.

::: tip Examples:
``` scheme
> (def lst [])
> (pop! lst)
#f
> (push! 10 lst)
> (push! 20 lst)
> (pop! lst)
20
> (pop! lst)
10
> (pop! lst)
#f
```
:::

### flatten
``` scheme
(flatten lst) -> list
Expand Down Expand Up @@ -2427,12 +2538,12 @@ group consecutive elements of the list `lst` into a list-of-lists.

::: tip Examples:
``` scheme
(group [1 2 2 3 1 1])
> ((1) (2 2) (3) (1 1))
> (group [1 2 2 3 1 1])
((1) (2 2) (3) (1 1))
(import :std/sort)
(group (sort [1 2 2 3 1 1] <) eqv?)
> ((1 1 1) (2 2) (3))
> (import :std/sort)
> (group (sort [1 2 2 3 1 1] <) eqv?)
((1 1 1) (2 2) (3))
```
:::

Expand All @@ -2447,11 +2558,28 @@ according to the predicate.

::: tip Examples:
``` scheme
(every-consecutive? <= [1 2 2 3 10 100])
> #t
> (every-consecutive? <= [1 2 2 3 10 100])
#t
> (every-consecutive? < [5 1 8 9])
#f
```
:::

### first-and-only
``` scheme
(first-and-only lst)
```
returns the first and only value of a singleton list,
or raises an error if the argument wasn't a singleton list.

::: tip Examples:
``` scheme
> (first-and-only '(42))
42
(every-consecutive? < [5 1 8 9])
> #f
> (first-and-only '())
*** ERROR IN std/misc/list#first-and-only, [email protected] -- Assertion failed (and (pair? x) (null? (cdr x)))
```
:::

Expand Down Expand Up @@ -2597,6 +2725,38 @@ the variable (or struct field) with the result of it.
```
:::

### acons
``` scheme
(acons k v alist) -> alst
k := key
v := value
alist := association list
alst := new association list with additional binding
```

Adds a new key-value pair to an existing alist in a pure way, a bit like `aset`.
Unlike `aset` and its friends, however, `acons` does *not* try to replace older bindings
for the same key, and will instead shadow them.
This can cause performance issues if a same key is used a lot of times with `acons`,
with the list growing ever longer; this can cause even more interesting correctness issues
if `arem` is used subsequently used, which will remove only the most recent binding,
revealing the previous one again, which may or may not be the desired behavior.
Thus, we recommend only using `acons` when you otherwise know `k` is not yet bound in the alist.

`acons` is analogous to the same-named function from Common Lisp, and
`(acons k v l)` is synonymous with `(cons (cons k v) l)`.

::: tip Examples:
```scheme
> (acons 1 "a" '((2 . "b") (3 . "c")))
((1 . "a") (2 . "b") (3 . "c"))
> (acons 1 "a" '((1 . "b")))
((1 . "a") (1 . "b"))
```
:::

## P-List utilities
Utilities to manipulate plists, i.e. property lists,
i.e. even-length lists where each even-indexed element is a key,
Expand Down Expand Up @@ -6957,6 +7117,8 @@ of the previous value and the provided arguments.
Given a list `<l>` or any thing you can iterate on, and a function `<f>`,
`xmin/map` returns the lower bound of the images by `<f>` of the items in `<l>`,
and of a `<base>` real, by default `+inf.0` (the positive infinity).
The function is short-circuiting and will not evaluate further values and their side-effects
after the bottom value `-inf.0` is reached.

### xmax
``` scheme
Expand Down Expand Up @@ -6991,3 +7153,38 @@ of the previous value and the provided arguments.
Given a list `<l>` or any thing you can iterate on, and a function `<f>`,
`xmax/map` returns the upper bound of the images by `<f>` of the items in `<l>`,
and of a `<base>` xreal, by default `-inf.0` (the negative infinity).
The function is short-circuiting and will not evaluate further values and their side-effects
after the top value `+inf.0` is reached.

### increment!, pre-increment!, post-increment!, decrement!, pre-decrement!, post-decrement!
``` scheme
(increment! place) -> (void)
(increment! place increment ...) -> (void)
(pre-increment! place) -> number
(pre-increment! place increment ...) -> number
(post-increment! place) -> number
(post-increment! place increment ...) -> number
(decrement! place) -> (void)
(decrement! place decrement ...) -> (void)
(pre-decrement! place) -> number
(pre-decrement! place decrement ...) -> number
(post-decrement! place) -> number
(post-decrement! place decrement ...) -> number
```

These macro will modify a variable or other place containing a number
to increment (respectively, decrement) its value, adding to it (respectively, subtracting from it)
one (if no further argument is specified) or the provided arguments (if specified).
*increment!* and *decrement!* return `#!void`,
*pre-increment!* and *pre-decrement!* return the value after addition (respectively, subtraction), and
*post-increment!* and *post-decrement!* return the value before addition (respectively, subtraction).

### make-counter
``` scheme
(make-counter) -> counter
(make-counter n) -> counter
```

This function creates a new counter, a function that takes zero or more arguments,
adds the sum of these arguments to the counter (or `1`, not `0`, if no argument was provided),
and returns the original value of the counter before the addition.
2 changes: 1 addition & 1 deletion src/std/build-deps
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,7 @@
"text/utf32"
(gerbil/core gerbil/gambit/fixnum std/error std/misc/bytes))
(std/misc/number "misc/number" (gerbil/core std/srfi/1 std/sugar))
(std/misc/hash "misc/hash" (gerbil/core gerbil/gambit/hash std/sort))
(std/misc/hash "misc/hash" (gerbil/core gerbil/gambit/hash std/iter std/sort))
(std/misc/path "misc/path" (gerbil/core))
(std/misc/symbol "misc/symbol" (gerbil/core))
(std/make
Expand Down
4 changes: 4 additions & 0 deletions src/std/misc/alist-test.ss
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,8 @@
(check-equal? (aremq 'c [['a . 1]['b . 2]]) [['a . 1]['b . 2]])
(check-equal? (aremq 'a []) [])
(check-equal? (aremq 'a [['a . 1]]) []))
(test-case "test acons"
(check-equal? (acons 'a 1 [['b . 2]]) [['a . 1]['b . 2]])
(check-equal? (acons [] [] []) [[[]]])
(check-equal? (acons 'a 10 [['a . 1]['b . 2]]) [['a . 10]['a . 1]['b . 2]])
))
3 changes: 3 additions & 0 deletions src/std/misc/alist.ss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
(export
alist?
plist->alist
acons
asetq asetv aset asetq! asetv! aset! assq-set! assv-set! assoc-set!
aremq aremv arem aremq! aremv! arem!)

Expand Down Expand Up @@ -41,6 +42,8 @@
(else
[[key . val] . lst])))))

(def (acons k v acc) [[k . v] . acc])

(define-aset asetq eq?)
(define-aset asetv eqv?)
(define-aset aset equal?)
Expand Down
28 changes: 27 additions & 1 deletion src/std/misc/hash-test.ss
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@
(def h (hash ("a" 1) ("b" 2) ("c" 3) ("d" 4) ("e" 5)))
(check (hash-value-map h (lambda (x) (* x 2)))
=> (hash ("a" 2) ("b" 4) ("c" 6) ("d" 8) ("e" 10))))
(test-case "hash-key-value-map"
(def h (hash ("a" 1) ("b" 2) ("c" 3) ("d" 4) ("e" 5) ("f" 6)))
(check (hash-key-value-map (lambda (k v) (and (even? v) (cons (/ v 2) (string-append k k)))) h)
=> (hash (1 "bb") (2 "dd") (3 "ff"))))
(test-case "hash-filter"
(def h (hash ("a" 1) ("b" 2) ("c" 3) ("d" 4) ("e" 5)))
(check (hash-filter h (lambda (k v) (odd? v)))
Expand Down Expand Up @@ -84,4 +88,26 @@
(hash (0 20) (2 22) (4 24) (6 26) (8 28))
(hash (3 33) (6 36) (9 39)))
=> h)
(check h => (hash (0 20) (1 11) (2 22) (3 33) (4 24) (5 15) (6 36) (7 17) (8 28) (9 39))))))
(check h => (hash (0 20) (1 11) (2 22) (3 33) (4 24) (5 15) (6 36) (7 17) (8 28) (9 39))))
(test-case "hash-get-set!, hash-ref-set!"
(def h (hash (1 11) (2 12) (3 13)))
(check (hash-get h 2) => 12)
(hash-get-set! h 2 22)
(check (hash-get h 2) => 22)
(hash-ref-set! h 2 32)
(check (hash-get h 2) => 32)
(hash-ref-set! h 2 5 42)
(check (hash-get h 2) => 42)
(hash-get-set! h 2 "b")
(check (hash-get h 2) => "b")
(set! (hash-get h 2) "B")
(check (hash-get h 2) => "B")
(hash-ref-set! h "a" 1)
(check (hash-get h "a") => 1)
(set! (hash-ref h "b") 2)
(check (hash-get h "b") => 2)
(defrules post-increment! () ((p x) (p x 1)) ((p x y ...) (begin0 x (set! x (+ x y ...)))))
(check (post-increment! (hash-ref h "a") 10) => 1)
(check (post-increment! (hash-ref h "a" 0)) => 11)
(check (post-increment! (hash-ref h "c" 0)) => 0)
(check (post-increment! (hash-ref h "c" 0)) => 1))))
Loading

0 comments on commit 3f248e1

Please sign in to comment.