Skip to content
Björn Lindqvist edited this page May 27, 2016 · 106 revisions

Tricks and Non-obvious Patterns

Getting the vocabs own path

Check the type of a tuple

Very simple:

USE: compression.zlib
IN: scratchpad T{ compressed } class-of .
compressed

Fallback for Missing Value

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 ;

Alien

See Tips and Tricks/Alien

Common Algorithms

Generate Candidates Until One Satisfies a Criteria

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

Cloning a Nested Data Structure

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.

CSV

Save a Two Dimensional Data Structure as a CSV

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.

Filesystem

See Tips and Tricks/Filesystem

Calendar

Generating Time Series

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 

Math

See Tips and Tricks/Math

Graphics programming

See Tips and Tricks/Graphics

Web programming

See Tips and Tricks/Web

Process management

See Tips and Tricks/Processes

String handling

See Tips and Tricks/Strings

Sequence processing

See Tips and Tricks/Sequences

Threads

See Tips and Tricks/Threads

Socket Programming

See Tips and Tricks/Sockets

UI

See Tips and Tricks/UI

Introspection

See Tips and Tricks/Introspection