Re: Factor

Factor: the language, the theory, and the practice.

Relative Time for Humans

Thursday, May 13, 2010

#time

Many applications deal with events that have occurred at different points in time. Often, these times are relatively recent, such as a list of emails in an inbox or a list of status updates on a social network. When we talk about when an event occurred, it is sometimes useful to be precise (e.g., Thu May 13 19:12:02 2010), and other times it is better to be a bit softer (e.g., about a minute ago).

This function gets built from time-to-time in various languages: for example in Python and Javascript. I thought it might be fun to see how simple it could be in Factor.

A very useful type of conditional combinator is called cond. It applies to a sequence of quotations. The first elements in the sequence are pairs of quotations. The combinator proceeds to call the first quotation in each pair until a true value is yielded, at which point it calls the second quotation in that pair and stops iterating. A final quotation can be provided to handle the case where none of the pairs returned a true value.

In typical applicative languages, this would be provided by an “if/else if/else” chain. It is a general pattern and is used in Factor to implement case (a type of switch statement).

Using a few vocabularies:

USING: combinators formatting kernel math ;

We will write a word that takes the number of seconds that something happened in the past, and calculates how long ago it was in “human terms”:

: relative-time ( seconds -- string )
    dup 0 < [ "negative seconds" throw ] when {
        { [ dup 1 < ] [ drop "just now" ] }
        { [ dup 60 < ] [ drop "less than a minute ago" ] }
        { [ dup 120 < ] [ drop "about a minute ago" ] }
        { [ dup 2700 < ] [ 60 / "%d minutes ago" sprintf ] }
        { [ dup 5400 < ] [ drop "about an hour ago" ] }
        { [ dup 86400 < ] [ 3600 / "%d hours ago" sprintf ] }
        { [ dup 172800 < ] [ drop "1 day ago" ] }
        [ 86400 / "%d days ago" sprintf ]
    } cond ;

Fairly concise as it turns out. If it wasn’t for the minor stack manipulation, you might say this was getting very close to the essence of the algorithm.