It is now time to start writing your functions in files and learn how to import them in the listener. Factor organizes words into nested namespaces called
vocabularies. You can import all names from a vocabulary with the word
USE:. In fact, you may have seen something like
USE: ranges
when you asked the listener to import the word
[1..b] for you. You can also use more than one vocabulary at a time with the word
USING:, which is followed by a list of vocabularies and terminated by
;, like
USING: ranges sequences ;
Finally, you define the vocabulary where your definitions are stored with the word
IN:. If you search the online help for a word you have defined so far, like
prime?, you will see that your definitions have been grouped under the default
scratchpad vocabulary. By the way, this shows that the online help automatically collects information about your own words, which is a very useful feature.
There are a few more words, like
QUALIFIED:,
FROM:,
EXCLUDE: and
RENAME:, that allow more fine-grained control over the imports, but
USING: is the most common.
On disk, vocabularies are stored under a few root directories, much like with the classpath in JVM languages. By default, the system starts looking up into the directories
basis,
core,
extra,
work under the Factor home. You can add more, both at runtime with the word
add-vocab-root, and by creating a configuration file
.factor-rc, but for now we will store our vocabularies under the
work directory, which is reserved for the user.
Generate a template for a vocabulary writing
USE: tools.scaffold
"github.tutorial" scaffold-work
You will find a file
work/github/tutorial/tutorial.factor containing an empty vocabulary. Factor integrates with many editors, so you can try
"github.tutorial" edit: this will prompt you to choose your favourite editor, and use that editor to open the newly created vocabulary.
You can add the definitions of the previous paragraph, so that it looks like
! Copyright (C) 2014 Andrea Ferretti.
! See https://factorcode.org/license.txt for BSD license.
USING: ;
IN: github.tutorial
: [2..b] ( n -- {2,...,n} ) 2 swap [a..b] ; inline
: multiple? ( a b -- ? ) swap divisor? ; inline
: prime? ( n -- ? )
[ sqrt [2..b] ] [ [ multiple? ] curry ] bi any? not ;
Since the vocabulary was already loaded when you scaffolded it, we need a way to refresh it from disk. You can do this with
"github.tutorial" refresh. There is also a
refresh-all word, with a shortcut
F2.
You will be prompted a few times to use vocabularies, since your
USING: statement is empty. After having accepted all of them, Factor suggests you a new header with all the needed imports:
USING: kernel math.functions ranges sequences ;
IN: github.tutorial
Now that you have some words in your vocabulary, you can edit, say, the
multiple? word with
\ multiple? edit. You will find your editor open on the relevant line of the right file. This also works for words in the Factor distribution, although it may be a bad idea to modify them.
This
\ word requires a little explanation. It works like a sort of escape, allowing us to put a reference to the next word on the stack, without executing it. This is exactly what we need, because
edit is a word that takes words themselves as arguments. This mechanism is similar to quotations, but while a quotation creates a new anonymous function, here we are directly referring to the word
multiple?.
Back to our task, you may notice that the words
[2..b] and
multiple? are just helper functions that you may not want to expose directly. To hide them from view, you can wrap them in a private block like this
<PRIVATE
: [2..b] ( n -- {2,...,n} ) 2 swap [a..b] ; inline
: multiple? ( a b -- ? ) swap divisor? ; inline
PRIVATE>
After making this change and refreshed the vocabulary, you will see that the listener is not able to refer to words like
[2..b] anymore. The
<PRIVATE word works by putting all definitions in the private block under a different vocabulary, in our case
github.tutorial.private.
You can have more than one
<PRIVATE block in a vocabulary, so feel free to organize them as you find necessary.
It is still possible to refer to words in private vocabularies, as you can confirm by searching for
[2..b] in the browser, but of course this is discouraged, since people do not guarantee any API stability for private words. Words under
github.tutorial can refer to words in
github.tutorial.private directly, like
prime? does.