]> gitweb.factorcode.org Git - factor.git/commitdiff
rename contains to contains? for consistency
authorSlava Pestov <slava@factorcode.org>
Tue, 24 Aug 2004 19:11:10 +0000 (19:11 +0000)
committerSlava Pestov <slava@factorcode.org>
Tue, 24 Aug 2004 19:11:10 +0000 (19:11 +0000)
TODO.FACTOR.txt
doc/devel-guide.tex
library/lists.factor
library/test/lists/lists.factor
library/test/random.factor
library/test/test.factor

index c0628be83f9d6c7f4ce753b4300fd088c98bbd86..f1393db0785dcd1b76a4996837fed84e62905548 100644 (file)
@@ -1,10 +1,31 @@
+- add a socket timeout\r
+- don't allow multiple reads on the same port\r
+  (and don't hang when this happends!)\r
+- >lower, >upper for strings\r
+- telnetd should use multitasking\r
+- telnetd error handling\r
+- accept multi-line input in listener\r
+- telnetd: send errors on socket\r
+\r
 + docs:\r
 \r
-- unparse examples\r
+- numbers section\r
+- examples of assoc usage\r
+- unparse examples, and difference from prettyprint\r
 - review doc formatting with latex2html\r
-- recursion -vs- iteration in vectors chapter\r
-- objects chapter covering namespaces, hashtables, equality and\r
-  object identity.\r
+- recursion -vs- iteration in vectors chapter, and combinator\r
+  construction\r
+- <% % %> and [, , ,] -- mention that % and , are usually in nested\r
+  words\r
+- object identity and equality - eq? and =\r
+- finish namespaces docs\r
+- mention word accessors/mutators\r
+- to document:\r
+  >r r> (earlier on?)\r
+  continuations\r
+  streams\r
+  multitasking\r
+  unit testing\r
 \r
 + tests:\r
 \r
 \r
 + native:\r
 \r
-- add a socket timeout\r
-- don't allow multiple reads on the same port\r
-  (and don't hang when this happends!)\r
 - is the profiler using correct stack depth?\r
 - bignums\r
-- >lower, >upper for strings\r
 - read1\r
-- telnetd should use multitasking\r
-- telnetd error handling\r
 - sbuf-hashcode\r
 - vector-hashcode\r
 - irc: stack underflow?\r
-- accept multi-line input in listener\r
 - gc call in the middle of some ops might affect callstack\r
 - better i/o scheduler\r
 \r
@@ -61,7 +75,9 @@
 \r
 + misc:\r
 \r
-- jvm factor -- still supporting httpd?\r
+- worddef>list ==> word-parameter\r
+- alist -vs- assoc terminology\r
+- unique,\r
 - dissolve builtins vocabulary\r
 - ifte* combinator\r
 - 'cascading' styles\r
@@ -71,8 +87,6 @@
 - namespace clone drops static var bindings\r
 - ditch expand\r
 - set-object-path\r
-- telnetd: send errors on socket\r
-- contains ==> contains?\r
 \r
 + httpd:\r
 \r
index 2aa88c38f529eab4b04f066f4ace80ab515406e8..56ae8a099b507db02deaa8b1311259ac6452eccf 100644 (file)
 
 Factor is an imperative programming language with functional and object-oriented
 influences. Its primary focus is the development of web-based server-side
-applications. Factor is run by a virtual machine that provides
-garbage collection and prohibits pointer arithmetic.%
-\footnote{Two releases of Factor are available -- a virtual machine written
-in C, and an interpreter written in Java that runs on the Java virtual
-machine. This guide targets the C version of Factor.%
-}
+applications. Factor borrows heavily from Forth, Joy and Lisp. Programmers familiar with these languages will recognize many similarities with Factor.
+
+Factor is \emph{interactive}. This means it is possible to run a Factor interpreter that reads from the keyboard, and immediately executes expressions as they are entered. This allows words to be defined and tested one at a time.
+
+Factor is \emph{dynamic}. This means that all objects in the language are fully reflective at run time, and that new definitions can be entered without restarting the interpreter. Factor code can be used interchangably as data, meaning that sophisticated language extensions can be realized as libraries of words.
 
-Factor borrows heavily from Forth, Joy and Lisp. From Forth it inherits
-a flexible syntax defined in terms of ``parsing words'' and an
-execution model based on a data stack and call stack. From Joy and
-Lisp it inherits a virtual machine prohibiting direct pointer arithmetic,
-and the use of ``cons cells'' to represent code and data structure.
+Factor is \emph{safe}. This means all code executes in a virtual machine that provides
+garbage collection and prohibits direct pointer arithmetic. There is no way to get a dangling reference by deallocating a live object, and it is not possible to corrupt memory by overwriting the bounds of an array.
+
+When examples of interpreter interactions are given in this guide, the input is in a roman font, and any
+output from the interpreter is in italics:
 
+\begin{alltt}
+"Hello, world!" print
+\emph{Hello, world!}
+\end{alltt}
 
 \section{Fundamentals}
 
@@ -51,14 +54,27 @@ A ``word'' is the main unit of program organization
 in Factor -- it corresponds to a ``function'', ``procedure''
 or ``method'' in other languages.
 
-When code examples are given, the input is in a roman font, and any
-output from the interpreter is in italics:
+A typical Factor development session involves a text editor and Factor
+interpreter running side by side. Instead of the edit/compile/run
+cycle, the development process becomes an {}``edit cycle'' -- you
+make some changes to the source file and reload it in the interpreter
+using a command like this:
 
 \begin{alltt}
-"Hello, world!" print
-\emph{Hello, world!}
+"numbers-game.factor" run-file
 \end{alltt}
 
+Then the changes can be tested, either by hand, or using a test harness.
+There is no need to compile anything, or to lose interpreter state
+by restarting. Additionally, words with {}``throw-away'' definitions
+that you do not intend to keep can also be entered directly at this
+interpreter prompt.
+
+Factor emphasizes \emph{bottom-up design}. Each word should do one useful task. New words can be defined in terms
+of existing, already-tested words. You design a set of reusable words
+that model the problem domain. Then, the problem is solved in terms
+of a \emph{domain-specific vocabulary}, and Factor programs are really just libraries of ureusable words.
+
 \subsection{The stack}
 
 The stack is used to exchange data between words. When a number is
@@ -340,16 +356,6 @@ a large number of words available for convenience, whereas
 source files should specify their external dependencies explicitly.%
 }
 
-New vocabularies are added to the search path using the \texttt{USE:}
-parsing word. For example:
-
-\begin{alltt}
-{}``/home/slava/.factor-rc'' exists? .
-\emph{ERROR: <interactive>:1: Undefined: exists?}
-USE: streams
-{}``/home/slava/.factor-rc'' exists? .
-\emph{t}
-\end{alltt}
 How do you know which vocabulary contains a word? Vocabularies can
 either be listed, and ``apropos'' searches can be performed:
 
@@ -370,6 +376,18 @@ either be listed, and ``apropos'' searches can be performed:
 \emph{(vector-map-step)}
 \emph{vector-map }
 \end{alltt}
+
+New vocabularies are added to the search path using the \texttt{USE:}
+parsing word. For example:
+
+\begin{alltt}
+"/home/slava/.factor-rc" exists? .
+\emph{ERROR: <interactive>:1: Undefined: exists?}
+USE: streams
+"/home/slava/.factor-rc" exists? .
+\emph{t}
+\end{alltt}
+
 New words are defined in the \emph{input vocabulary}. The input vocabulary
 can be changed at the interactive prompt, or in a source file, using
 the \texttt{IN:} parsing word. For example:
@@ -410,35 +428,6 @@ numbers-game
 \emph{Correct - you win!}
 \end{alltt}
 
-\subsection{Development methodology}
-
-A typical Factor development session involves a text editor and Factor
-interpreter running side by side. Instead of the edit/compile/run
-cycle, the development process becomes an {}``edit cycle'' -- you
-make some changes to the source file and reload it in the interpreter
-using a command like this:
-
-\begin{alltt}
-"numbers-game.factor" run-file
-\end{alltt}
-Then the changes can be tested, either by hand, or using a test harness.
-There is no need to compile anything, or to lose interpreter state
-by restarting. Additionally, words with {}``throw-away'' definitions
-that you do not intend to keep can also be entered directly at this
-interpreter prompt.
-
-Each word should do one useful task. New words can be defined in terms
-of existing, already-tested words. You design a set of reusable words
-that model the problem domain. Then, the problem is solved in terms
-of a \emph{domain-specific vocabulary}. This is called \emph{bottom-up
-design.}
-
-The jEdit text editor makes Factor development much more pleasant.
-The Factor plugin for jEdit provides an {}``integrated development
-environment'' with many time-saving features. See the documentation
-for the plugin itself for details.
-
-
 \subsection{Getting started}
 
 Start a text editor and create a file named \texttt{numbers-game.factor}.
@@ -685,10 +674,15 @@ USE: stack
 : numbers-game number-to-guess numbers-game-loop ;
 \end{verbatim}
 
+\section{Numbers}
+
+Arithmetic operations, number tower, deconstructing ratios and complex, irrational functions, numerical integration.
+
 \section{Lists}
 
-A list is composed of a set of pairs; each pair holds a list element,
-and a reference to the next pair. Lists have the following literal
+A list of objects is realized as a set of pairs; each pair holds a list element,
+and a reference to the next pair. All words relating to cons cells and lists are found in the \texttt{lists}
+vocabulary.  Lists have the following literal
 syntax:
 
 \begin{alltt}
@@ -721,8 +715,7 @@ A cons cell is an object that holds a reference to two other objects.
 The order of the two objects matters -- the first is called the \emph{car},
 the second is called the \emph{cdr}.
 
-All words relating to cons cells and lists are found in the \texttt{lists}
-vocabulary. The words \texttt{cons}, \texttt{car} and \texttt{cdr}%
+The words \texttt{cons}, \texttt{car} and \texttt{cdr}%
 \footnote{These infamous names originate from the Lisp language. Originally,
 {}``Lisp'' stood for {}``List Processing''.%
 } construct and deconstruct cons cells:
@@ -759,7 +752,7 @@ is a proper list, and in fact it is equivalent to the empty list \texttt{{[}
 {]}}. An \emph{improper list} is a set of cons cells that does not terminate with \texttt{f}. Improper lists are input with the following syntax:
 
 \begin{verbatim}
-{[} 1 2 3 | 4 {]}
+[ 1 2 3 | 4 ]
 \end{verbatim}
 
 The \texttt{list?} word tests if the object at the top of the stack
@@ -943,21 +936,21 @@ is suggestive:
 \texttt{assoc? ( obj -{}- ? )} returns \texttt{t} if the object is
 a list whose every element is a cons; otherwise it returns \texttt{f}.
 
-\texttt{assoc ( name alist -{}- value )} looks for a pair with this
-name in the list, and pushes the cdr of the pair. Pushes f if no pair
-with this name is present. Note that \texttt{assoc} cannot differentiate between
-a name that is not present at all, or a name with a value of \texttt{f}.
+\texttt{assoc ( key alist -{}- value )} looks for a pair with this
+key in the list, and pushes the cdr of the pair. Pushes f if no pair
+with this key is present. Note that \texttt{assoc} cannot differentiate between
+a key that is not present at all, or a key with a value of \texttt{f}.
 
-\texttt{assoc{*} ( name alist -{}- {[} name | value {]} )} looks for
-a pair with this name, and pushes the pair itself. Unlike \texttt{assoc},
+\texttt{assoc{*} ( key alist -{}- {[} key | value {]} )} looks for
+a pair with this key, and pushes the pair itself. Unlike \texttt{assoc},
 \texttt{assoc{*}} returns different values in the cases of a value
 set to \texttt{f}, or an undefined value.
 
-\texttt{set-assoc ( value name alist -{}- alist )} removes any existing
-occurrence of a name from the list, and adds a new pair. This creates
+\texttt{set-assoc ( value key alist -{}- alist )} removes any existing
+occurrence of a key from the list, and adds a new pair. This creates
 a new list, the original is unaffected.
 
-\texttt{acons ( value name alist -{}- alist )} is slightly faster
+\texttt{acons ( value key alist -{}- alist )} is slightly faster
 than \texttt{set-assoc} since it simply conses a new pair onto the
 list. However, if used repeatedly, the list will grow to contain a
 lot of {}``shadowed'' pairs.
@@ -1271,18 +1264,18 @@ A pair of combinators for iterating over vectors are provided in the \texttt{vec
 
 \texttt{vector-each ( vector quot -{}- )} pushes each element of the vector in turn, and executes the quotation. The quotation should have a stack effect of \texttt{( obj -- )}. The vector and the quotation are not on the stack when the quotation is executed. This allows the quotation to use values below the vector for accumilation and so on.
 
-The \texttt{vector>list} word is defined as first creating a list of all elements in the vector in reverse order, and then reversing this list:
+The \texttt{stack>list} word makes use of \texttt{vector-each} to construct a list containing all elements of a given vector, in reverse order. In fact, its definition looks exactly like that of \texttt{reverse} except the \texttt{vector-each} combinator is used in place of \texttt{each}:
 
 \begin{alltt}
-: vector>list ( vector -- list )
-    stack>list nreverse ;
+: stack>list ( vector -- list )
+    {[} {]} swap {[} swons {]} vector-each ;
 \end{alltt}
 
-The \texttt{stack>list} word makes use of \texttt{vector-each} to construct the list. In fact, its definition looks exactly like that of \texttt{reverse} except the \texttt{vector-each} combinator is used in place of \texttt{each}:
+The \texttt{vector>list} word is defined as first creating a list of all elements in the vector in reverse order using \texttt{stack>list}, and then reversing this list:
 
 \begin{alltt}
-: stack>list ( vector -- list )
-    {[} {]} swap {[} swons {]} vector-each ;
+: vector>list ( vector -- list )
+    stack>list nreverse ;
 \end{alltt}
 
 \texttt{vector-map ( vector quot -{}- str )} is similar to \texttt{vector-each}, except after each iteration the return value of the quotation is collected into a new vector. The quotation should have a stack effect of \texttt{( obj -- obj )}.
@@ -1377,7 +1370,7 @@ buffer type which is the topic of the next section.
 \texttt{str-length ( str -{}- n )} pushes the length of a string:
 
 \begin{alltt}
-{}``Factor'' str-length .
+"Factor" str-length .
 \emph{6}
 \end{alltt}
 \texttt{str-nth ( n str -{}- ch )} pushes the character located by
@@ -1917,14 +1910,123 @@ All that remains now is the ``main word'' that runs the program with an empty ti
     10 <vector> main-menu ;
 \end{alltt}
 
-\section{Variables and namespaces}
+\subsection{The complete program}
+
+\begin{verbatim}
+! Contractor timesheet example
+
+IN: timesheet
+USE: arithmetic
+USE: combinators
+USE: errors
+USE: format
+USE: kernel
+USE: lists
+USE: parser
+USE: stack
+USE: stdio
+USE: strings
+USE: unparser
+USE: vectors
+
+! Adding a new entry to the time sheet.
 
+: measure-duration ( -- duration )
+    millis
+    read drop
+    millis swap - 1000 /i 60 /i ;
+
+: add-entry-prompt ( -- duration description )
+    "Start work on the task now. Press ENTER when done." print
+    measure-duration
+    "Please enter a description:" print
+    read ;
+
+: add-entry ( timesheet -- )
+    add-entry-prompt cons swap vector-push ;
+
+! Printing the timesheet.
+
+: hh ( duration -- str ) 60 /i ;
+: mm ( duration -- str ) 60 mod unparse 2 digits ;
+: hh:mm ( millis -- str ) <% dup hh % ":" % mm % %> ;
+
+: print-entry ( duration description -- )
+    dup write
+    60 swap pad-string write
+    hh:mm print ;
+
+: print-timesheet ( timesheet -- )
+    "TIMESHEET:" print
+    [ uncons print-entry ] vector-each ;
+
+! Displaying a menu
+
+: print-menu ( menu -- )
+    terpri [ cdr car print ] each terpri
+    "Enter a letter between ( ) to execute that action." print ;
+
+: menu-prompt ( menu -- )
+    read swap assoc dup [
+        cdr call
+    ] [
+        "Invalid input: " swap unparse cat2 throw
+    ] ifte ;
+
+: menu ( menu -- )
+    dup print-menu menu-prompt ;
+
+! Main menu
+
+: main-menu ( timesheet -- )
+    [
+        [ "e" "(E)xit" drop ]
+        [ "a" "(A)dd entry" dup add-entry main-menu ]
+        [ "p" "(P)rint timesheet" dup print-timesheet main-menu ]
+    ] menu ;
+
+: timesheet-app ( -- )
+    10 <vector> main-menu ;
+\end{verbatim}
+
+\section{Object orientation}
+
+\subsection{Identity and equality}
 
 \subsection{Hashtables}
 
+A hashtable, much like an association list, stores key/value pairs, and offers lookup by key. However, whereas an association list must be searched linearly to locate keys, a hashtable uses a more sophisticated method. Key/value pairs are sorted into \emph{buckets} using a \emph{hash function}. If two objects are equal, then they must have the same hash code; but not necessarily vice versa. To look up the value associated with a key, only the bucket corresponding to the key has to be searched. A hashtable is simply a vector of buckets, where each bucket is an association list.
+
+\texttt{<hashtable> ( capacity -{}- hash )} creates a new hashtable with the specified number of buckets. A hashtable with one bucket is basically an association list. Right now, a ``large enough'' capacity must be specified, and performance degrades if there are too many key/value pairs per bucket. In a future implementation, hashtables will grow as needed as the number of key/value pairs increases.
+
+\texttt{hash ( key hash -{}- value )} looks up the value associated with a key in the hashtable. Pushes \texttt{f} if no pair with this key is present. Note that \texttt{hash} cannot differentiate between a key that is not present at all, or a key with a value of \texttt{f}.
+
+\texttt{hash* ( key hash -{}- {[} key | value {]})} looks for
+a pair with this key, and pushes the pair itself. Unlike \texttt{hash},
+\texttt{hash{*}} returns different values in the cases of a value
+set to \texttt{f}, or an undefined value.
+
+\texttt{set-hash ( value key hash -{}- )} stores a key/value pair in a hashtable.
+
+examples, and hash>alist, hash-keys, hash-values
+
+\subsection{Variables}
+
+Notice that until now, all the code except a handful of examples has only used the stack for storage. You can also use variables to store temporary data, much like in other languages, however their use is not so prevalent. This is not a coincidence -- Fator was designed this way, and mastery of the stack is essential. Using variables where the stack is more appropriate leads to ugly, unreusable code.
+
+Variables are typically used for longer-term storage of data, and for temporary storage of objects that are being constructed, where using the stack would be ackward. Another use for variables is compound data structures, realized as nested namespaces of variables. This concept should be instantly familiar to anybody who's used an object-oriented programming language.
+
+The words \texttt{get ( name -{}- value )} and \texttt{set ( value name -{}- )} retreive and store variable values, respectively. For example:
+
+blah blah
 
 \subsection{Namespaces}
 
+describe bind and extend combinators
+
+namespaces are hashtables
+
+values, vars, vars-values
 
 \subsection{The name stack}
 
@@ -1948,12 +2050,6 @@ The name stack is really just a vector. The words \texttt{>n} and \texttt{n>} ar
 : n> ( n:namespace -- namespace ) namestack* vector-pop ;
 \end{alltt}
 
-\subsection{The inspector}
-
-
-\section{PRACTICAL: Music player}
-
-
 \section{Metaprogramming}
 
 Recall that code quotations are in fact just linked lists. Factor code is data, and vice versa. Essentially, the interpreter iterates through code quotations, pushing literals and executing words. When a word is executed, one of two things happen -- either the word has a colon definition, and the interpreter is invoked recursively on the definition, or the word is primitive, and it is executed by the underlying virtual machine. A word is itself a first-class object.
index 8b9722d66a7ce3f2a0a48742b9eccbcc48cee44c..fbb332da3fdb957e86b640d6ea1a2b523da4c736 100644 (file)
@@ -81,16 +81,12 @@ USE: vectors
 : cddr ( list -- cddr )
     cdr cdr ; inline
 
-: contains ( element list -- remainder )
+: contains? ( element list -- remainder )
     #! If the proper list contains the element, push the
     #! remainder of the list, starting from the cell whose car
     #! is elem. Otherwise push f.
     dup [
-        2dup car = [
-            nip
-        ] [
-            cdr contains
-        ] ifte
+        2dup car = [ nip ] [ cdr contains? ] ifte
     ] [
         2drop f
     ] ifte ;
@@ -143,7 +139,7 @@ USE: vectors
 : next ( obj list -- obj )
     #! Push the next object in the list after an object. Wraps
     #! around to beginning of list if object is at the end.
-    tuck contains dup [
+    tuck contains? dup [
         ! Is there another entry in the list?
         cdr dup [
             nip car
@@ -238,11 +234,7 @@ DEFER: tree-contains?
 : unique ( elem list -- list )
     #! Prepend an element to a proper list if it is not
     #! already contained in the list.
-    2dup contains [
-        nip
-    ] [
-        cons
-    ] ifte ;
+    2dup contains? [ nip ] [ cons ] ifte ;
 
 : each ( list quotation -- )
     #! Push each element of a proper list in turn, and apply a
index 690283eb65976b955e39f1b1402c050eae3a03ec..4f7520f6d97c16cdae45d38a9bdbaca698682506 100644 (file)
@@ -23,10 +23,10 @@ USE: test
 
 [ t ] [ [ 1 2 ] [ 3 4 ] clone-list-actually-clones? ] unit-test
 
-[ f         ] [ 3 [ ]     contains ] unit-test
-[ f         ] [ 3 [ 1 2 ] contains ] unit-test
-[ [ 1 2 ]   ] [ 1 [ 1 2 ] contains ] unit-test
-[ [ 2 ]     ] [ 2 [ 1 2 ] contains ] unit-test
+[ f         ] [ 3 [ ]     contains? ] unit-test
+[ f         ] [ 3 [ 1 2 ] contains? ] unit-test
+[ [ 1 2 ]   ] [ 1 [ 1 2 ] contains? ] unit-test
+[ [ 2 ]     ] [ 2 [ 1 2 ] contains? ] unit-test
 
 [ 1 ] [  -1 [ 1 2 ] nth ] unit-test
 [ 1 ] [  0  [ 1 2 ] nth ] unit-test
index 8b8b98fc296f77c440243c73609840f560da1533..666fdea9be8279de7f6a1c24bae90ad043168a1e 100644 (file)
@@ -21,7 +21,7 @@ unit-test
 [ f ]
 [
     "random-pairs" get
-    random-element* [ t f "monkey" ] contains not
+    random-element* [ t f "monkey" ] contains? not
 ] unit-test
 
 : check-random-int ( min max -- )
index 2d3110c60d947cac9bfda4c4b26cda5f284fbb03..d347b015fbabfed7de7f6110a5aeffaeccc8468b 100644 (file)
@@ -45,6 +45,7 @@ USE: unparser
 : time ( code -- )
     #! Evaluates the given code and prints the time taken to
     #! execute it.
+    "Timing " write dup .
     millis >r call millis r> - . ;
 
 : test ( name -- )