Wednesday, February 25, 2009

cd factor

When working with Factor source code, you might find yourself moving between several directories on the filesystem, navigating and editing several files.

Due to source code being kept inside core, basis, extra, work, and other locations, it is not always a simple matter of moving up and down directories to find the files and vocabularies that you are looking for.

Today, I wrote a bit of bash script to simplify, and improve, this part of the development process.

# change directories to a factor module
cdfactor() {
    code=$(printf "USING: io io.pathnames vocabs vocabs.loader ; "
           printf "\"%s\" <vocab> vocab-source-path (normalize-path) print" $1)
    echo $code > $HOME/.cdfactor
    fn=$(factor $HOME/.cdfactor)
    dn=$(dirname $fn)
    echo $dn
    if [ -z "$dn" ]; then
        echo "Warning: directory '$1' not found" 1>&2
    else
        cd $dn
    fi
}

This function takes a vocabulary as argument. When run, it generates a temporary Factor script that is executed to find the pathname to the source file. It then changes directories into the directory containing the source file.

For example, if you want to switch to the io.files vocab, just run:

$ cdfactor io.files
Note: this requires factor to be on the $PATH.

Wednesday, February 18, 2009

Readline support for Factor

When using Factor from the command line, you might notice that it lacks many of the features of typical REPL's offered by other languages. For example, using arrow keys, home, end, delete, and backspace to navigate and edit text, and having proper history support for using previous lines of text.

These features are often implemented by using the GNU Readline library.

But, how do you use readline with Factor? The easiest way is to use the rlwrap command, which wraps an arbitrary command in readline.

To install it on Linux, run sudo yum install rlwrap (for RPM-based distros) or sudo apt-get install rlwrap (for Debian-based distros).

On the Mac, you can install it with the MacPorts system by running sudo port install rlwrap.

Once installed, add rlwrap in front of your factor command. For instance:

rlwrap ./factor

You should find interacting with Factor to be much easier.

Tuesday, December 23, 2008

GCD

The Factor IRC channel (#concatenative) can be a helpful resource when trying to learn how to code in Factor. Today, someone asked for help implementing the Greatest Common Denominator algorithm in Factor. There are a variety of algorithms for solving for the GCD of two numbers (and many are documented on the Wikipedia entry).

One possible solution uses the Euclidean Algorithm, which is implemented like so:

def gcd(a, b):
    if b = 0:
        return a
    else:
        return gcd(b, a % b)

We can translate that fairly directly to a recursive Factor word:

: gcd ( a b -- c )
    dup zero?
    [ drop ]
    [ [ mod ] keep swap gcd ]
    if ;

It's worth noting that Factor has a builtin word gcd in the math vocabulary calculating this problem.

To learn how it works:

( scratchpad ) USE: math

( scratchpad ) \ gcd help

To see how it is implemented:

( scratchpad ) USE: math

( scratchpad ) \ gcd see

Monday, December 15, 2008

Tuesday, December 9, 2008

wp.factor

I came across a benchmark for comparing languages today. It did not contain a version for Factor, so I thought I would contribute one.

The idea is fairly straightforward, and in the words of the author:

read stdin, tokenize into words
for each word count how often it occurs
output words and counts, sorted in descending order by count

My attempt is below:

USING: arrays assocs kernel io math math.parser 
prettyprint sequences splitting sorting ;

IN: wp

: count-words ( assoc string -- assoc' )
    " " split harvest [ over inc-at ] each ;

: sort-assoc ( assoc -- seq )
    >alist sort-values reverse ;

: print-results ( seq -- )
    [ number>string "    " glue print ] assoc-each ;

: wp ( -- )
    H{ } clone
    [ [ count-words ] each-line ]
    [ sort-assoc print-results ]
    bi drop ;

MAIN: wp

You can run this from factor by putting it in a file called wp.factor and running from the shell:

cat file.txt | ./factor -run=wp

Thursday, October 2, 2008

Clamp

One occasionally useful snippet of code when working with numbers is the clamp function for restricting a number to a range of values (either the minimum, maximum, or somewhere in-between).

In a language like Python or C or Java, one might write this function:

def clamp(a, value, b):
    return max(a, min(b, value))

In Factor, this is written in a similar, but more terse, manner:

: clamp ( a value b -- x )
    min max ;

Since the arguments are located on the stack, the "min" word operates on "value" and "b", placing the "result" on the stack, then the "max" word operates on "a" and "result", placing the final result on the stack.

Simple. Elegant.

Factor

Factor is a high-level language written by Slava Pestov with many interesting characteristics.  

It is stack-based with high-level features including dynamic types, extensible syntax, macros, and garbage collection.  On a practical side, Factor has a mature library, supports many different platforms, and has been extensively documented.  Similar in many ways to other concatenative programming languages, the syntax could be considered terse, but powerful.

It is a very different language than most with a lot of potential for its future.  

This blog will contain articles and code related to Factor, and should serve as both a learning guide and exploration of this language.