-
Notifications
You must be signed in to change notification settings - Fork 2
Tips and tricks
Very simple:
USE: compression.zlib
IN: scratchpad T{ compressed } class-of .
compressed
Suppose you have a value that may be false. Such as a string which represents the username or is false if no user has logged in. Then you can coerce the value to a string like this:
: ensure-username ( username/f -- username' )
"Unknown user" or ;
This is similar to how COALESCE
works in SQL, or the null-coalescing operator ??
works in C#:
select coalesce(username, 'Unknown user')
var u = username ?? "Unknown user"
Note that in Factor, unlike some other languages, an empty sequence or string is considered to be true. So to replace an empty string or sequence with a default value you would instead write:
: ensure-name ( name -- name' )
[ "Unknown user" ] when-empty ;
This situation often comes up when you want to get something random, but with a condition. The basic idea is to generate candidates and cull those until we find something suitable. Say we want to generate a random prime < 1000:
USE: math.primes
IN: [ 1000 random dup prime? ] [ drop ] until .
983
Although this is my preferred solution you could also solve the problem using the lists.lazy
vocab. Then we can create an infinite list of numbers, filter out those that are prime and taking the first one of them:
IN: USE: lists lists.lazy
IN: 1 [ drop 1000 random ] lfrom-by [ prime? ] lfilter car .
661
The clone
word only operates on the instance given to it so it is not enough if you want to perform a deep copy of a large object. But it is easy to write a word that recursively clones all parts of a nested tuple:
: deepclone ( tuple -- tuple' )
tuple>array [ dup tuple? [ deepclone ] [ clone ] if ] map >tuple ;
That's not good enough. It needs to be extended to work with other mutable types like vectors and hash tables.
This is incredibly easy using the csv vocab. Perhaps you have a list of celebrities with birth dates that you want to save:
IN: { { "Roger Moore" 1927 } { "Tom Cruise" 1962 } { "Marilyn Monroe" 1926 } }
IN: [ present ] matrix-map csv>string .
"Roger Moore,1927\nTom Cruise,1962\nMarilyn Monroe,1926\n"
IN: { { "Roger Moore" 1927 } { "Tom Cruise" 1962 } { "Marilyn Monroe" 1926 } }
IN: [ present ] matrix-map "celebs.csv" utf8 csv>file
The csv vocab expects all cells to be strings so we use the present
word to stringify the possibly non-stringy cells. You should absolutely prefer to use the csv vocab rather than the seemingly equivalent [ "," join ] map "\n" join
code because the former handles escaping and other weird special cases.
See Tips and Tricks/Filesystem
Generate all dates since January 1st of the current year:
IN: today 1 >>month 1 >>day
[ dup today <=> +lt+ = ] [ [ 1 days time+ ] keep ] produce nip