Category: Uncategorized
Factor Fun (Part 2)
It's time to have some fun with Factor and learn something in the process
. The purpose of this post is to demonstrate how to use tuples in Factor.
The Problem
My girlfriend works for a doctor as her personal assistant. (Yes, I have a REAL girlfriend
.) The doctor has 3 rooms filled with files. Each file has a unique number. Each room contains a specific sequence of file numbers:
- Room A : 1 - 20 000
- Room B : 20 001 - 40 000
- Room C : 40 001 - 70 000
Now, when the doctor sees a new patient, my g/f must physically fetch that patient's file from either room A, B, or C. But because she has a lot of other stuff to do there is no time to put back the file (and of coarse the doctor will not do it). So at the end of each week there is a pile of files that need to be put back in their respective rooms.
This isn't really a problem for her, but I thought it might make a good article that is simple to write and understand and explain a few concepts of Factor to the readers
.
Ok, so our program that we are going to write takes as input, a sequence of file numbers that need to be put away and basically sorts the files-to-put-away into a pile for each room.
The 1st Solution
USING: new-slots accessors math io prettyprint ;
! we are using NEW-SLOTS for this program because they will be replacing the old-style
! slots
! create a tuple to hold information for each room
TUPLE: room name start-num end-num files ;
C: <room> room
: show-room-info ( tuple -- )
dup files>> swap name>>
"Files for room [" swap "]:" 3append print
[ number>string print ] each ;
: sort-files ( seq -- )
! seq is a sequence of file numbers that need to be put back in their place.
! This word then calculates what files go to what room and displays the output.
! ---
V{ }
"A" 1 20000 V{ } <room> add
"B" 20001 40000 V{ } <room> add
"C" 40001 70000 V{ } <room> add
[
over
[
dup pick dup start-num>> swap end-num>> between?
[ over files>> swap add >>files ] [ drop ] if
] each
show-room-info
] each drop ;
In this solution things are a bit hard-coded and the abstraction is not fully complete. We need a way to define the "room" sequence and the files sequence and let the sort-files word do the rest. This will also allow us to specify any number of rooms that we might need. The idea, however, behind this post is to show how we use TUPLES: in Factor, not to show how to write complete abstractions
.
More About Tuples
To work with tuples, there are usually 2 steps :
- define the new tuple type
- create a constructor word for the tuple
To define a tuple, we write:
TUPLE: room name start-num end-num files ;
This defines a new tuple class called room with the following
slots:
- name
- start-num
- end-num
- files
To create an instance of the tuple class, we need to create a constructor word. Constructor words are used to initialize the slots of a tuple instance to known values. There are 2 general ways to do this:
- we can construct a new tuple with corresponding arguments on the stack.
- we can construct a new tuple with fixed slot values.
To create a constructor word that will take its initialization values from the stack, we write:
C: <room> room
or we can write:
: <room> room construct-boa ;
Both versions do exactly the same thing: it creates a constructor word that initializes the tuple instance's slot values with the corresponding values on the stack. The first version is shorter and cleaner to use if this is all that needs to be done when constructing a tuple instance. This type of constructor word is usually referred to as a "boa-constructor". (boa stands for: by order of arguments. This means that the slot values will be initialized in the order that the arguments are on the stack. E.g. slot1 will get argument 1 on stack, slot2 will get argument 2 on stack, etc.)
To create a constructor word that will initialize the tuple instance's slot values to fixed / pre-defined values we can create a constructor word like this:
: <room> room construct-empty "" >>name 0 >>start-num 0 >>end-num V{ } >>files ;
This constructor word creates a new room tuple instance and initializes the new instance's slots to known values. Using this method of construction, you can construct a tuple in any way imagineable (well, alomst
.
Constructor words have the following naming convention:
<constructor-word-name>
and should always be named like this if possible.
To get the value of a tuple slot, we use the new-slots vocab. This gives us access to the new way to work with tuple slots. To work with tuple slot, we type:
! create a new instance of the room tuple (using the boa-constructor):
"room A" 1 20000 V{ } <room>
! setting the 'name' tuple-slot's value:
"room B" >>name
! getting the value of the 'name' tuple-slot and printing it:
dup name>> print
Some Interesting Questions
-
What is the naming convention if you want 2 or more constructors for the same tuple? Maybe something like <room-foo> and <room-bar>. Any ideas are welcome.
-
Would it not be a good idea for the slot accessors to have a version that automatically duplicates the tuple and then retrieve the slot value?
Factor Fun (Part 1) Update
Hey everyone. After talking with littledan about the code I have decided to remove the "Factor Fun (part 1)" posts and will be updating the code to a better solution and merging the 2 posts into 1.