Sets are statically sized arrays. They are represented in memory as:
count
data #1 (first)
...
data #n (last)TODO:
[x] set:from-results
[x] set:from-string
[x] set:contains?
[x] set:contains-string?
[x] set:filter
[x] set:map
[x] set:for-each
[x] set:dup
[x] set:reverse
[x] set:nthThe first couple of words are used to create sets. The first, set:from-results executes a quote and constructs a set from the returned values.
:set:from-results (q-a)
depth [ call ] dip depth swap -
here [ dup , [ , ] times ] dip ;The second, set:from-string, creates a new string with the characters in given a string.
:set:from-string (s-a)
s:reverse [ [ ] s:for-each ] curry
set:from-results ;A very crucial piece is set:for-each. This runs a quote once against each value in a set. This will be leveraged to implement additional combinators.
{{
'Q var
---reveal---
:set:for-each (aq-)
@Q [ !Q fetch-next
[ fetch-next swap [ @Q call ] dip ] times drop
] dip !Q ;
}}With this I can easily define set:dup to make a copy of a set.
:set:dup (a-a)
here [ dup fetch , [ , ] set:for-each ] dip ;Next is set:filter, which is extracts matching values from a set. This is used like:
[ #1 #2 #3 #4 #5 #6 #7 #8 ] set
[ n:even? ] set:filterIt returns a new set with the values that the quote returned a TRUE flag for.
:set:filter (aq-)
[ over [ call ] dip swap [ , ] [ drop ] choose ] curry
here [ over fetch , set:for-each ] dip here over - n:dec over store ;Next are set:contains? and set:contains-string? which compare a given value to each item in the array and returns a flag.
{{
'F var
---reveal---
:set:contains? (na-f)
&F v:off
[ over eq? @F or !F ] set:for-each
drop @F ;
:set:contains-string? (na-f)
&F v:off
[ over s:eq? @F or !F ] set:for-each
drop @F ;
}}I implemented set:map to apply a quotation to each item in a set and construct a new set from the returned values.
Example:
[ #1 #2 #3 ] set
[ #10 * ] set:map:set:map (aq-)
[ call , ] curry
here [ over fetch , set:for-each ] dip ;You can use set:reverse to make a copy of a set with the values reversed. This can be useful after a set:from-results.
:set:reverse (a-a)
here [ fetch-next [ + n:dec ] sip dup ,
[ dup fetch , n:dec ] times drop
] dip ;set:nth provides a quick means of adjusting a set and offset into an address for use with fetch and store.
:set:nth (an-a)
+ n:inc ;