moved random number generation words to math vocabulary

cvs
Slava Pestov 2005-05-02 04:56:09 +00:00
parent f96779a56c
commit cd48ebebf6
6 changed files with 343 additions and 39 deletions

View File

@ -35,7 +35,7 @@
\newcommand{\genericword}[2]{\index{\texttt{#1}}\emph{Generic word:} \texttt{#2}&\\}
\newcommand{\predword}[1]{\ordinaryword{#1}{#1~( object -- ?~)}&\\}
\newcommand{\predword}[1]{\ordinaryword{#1}{#1~( object -- ?~)}}
\setlength{\tabcolsep}{1mm}
@ -65,12 +65,10 @@
\maketitle
\tableofcontents{}
\chapter*{Introduction}
\chapter*{Preface}
What follows is a detailed guide to the Factor language and development environment. It is not a tutorial or introductory guide, nor does it cover some background material that you are expected to understand, such as object-oriented programming, higher-order functions, continuations, or general issues of algorithm and program design.
\chapter{The language}
Factor is a programming language combinding a postfix syntax with a functional and object-oriented
flavor, building on ideas from Forth, Joy and Lisp.
@ -79,6 +77,267 @@ Factor is \emph{dynamic}. This means that all objects in the language are fully
Factor is \emph{safe}. This means all code executes in an object-oriented runtime 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.
\chapter{Tutorial}
\section{A number guessing game}
In this section, basic input/output and flow control is introduced.
We construct a program that repeatedly prompts the user to guess a
number -- they are informed if their guess is correct, too low, or
too high. The game ends on a correct guess.
\begin{alltt}
numbers-game
\emph{I'm thinking of a number between 0 and 100.}
\emph{Enter your guess:} 25
\emph{Too low}
\emph{Enter your guess:} 38
\emph{Too high}
\emph{Enter your guess:} 31
\emph{Correct - you win!}
\end{alltt}
\subsection{Getting started}
Start a text editor and create a file named \texttt{numbers-game.factor}.
Write a short comment at the top of the file. Two examples of commenting style supported by Factor:
\begin{alltt}
! Numbers game.
( The great numbers game )
\end{alltt}
It is always a good idea to comment your code. Try to write simple
code that does not need detailed comments to describe; similarly,
avoid redundant comments. These two principles are hard to quantify
in a concrete way, and will become more clear as your skills with
Factor increase.
We will be defining new words in the \texttt{numbers-game} vocabulary; add
an \texttt{IN:} statement at the top of the source file:
\begin{alltt}
IN: numbers-game
\end{alltt}
Also in order to be able to test the words, issue a \texttt{USE:}
statement in the interactive interpreter:
\begin{alltt}
USE: numbers-game
\end{alltt}
This section will develop the numbers game in an incremental fashion.
After each addition, issue a command like the following to load the
source file into the Factor interpreter:
\begin{alltt}
"numbers-game.factor" run-file
\end{alltt}
\subsection{Reading a number from the keyboard}
A fundamental operation required for the numbers game is to be able
to read a number from the keyboard. The \texttt{read} word \texttt{(
-{}- str )} reads a line of input and pushes it on the stack.
The \texttt{parse-number} word \texttt{( str -{}- n )} turns a decimal
string representation of an integer into the integer itself. These
two words can be combined into a single colon definition:
\begin{alltt}
: read-number ( -{}- n ) read parse-number ;
\end{alltt}
You should add this definition to the source file, and try loading
the file into the interpreter. As you will soon see, this raises an
error! The problem is that the two words \texttt{read} and \texttt{parse-number}
are not part of the default, minimal, vocabulary search path used
when reading files. The solution is to use \texttt{apropos.} to find
out which vocabularies contain those words, and add the appropriate
\texttt{USING:} statements to the source file:
\begin{alltt}
USING: parser stdio ;
\end{alltt}
After adding the above two statements, the file should now parse,
and testing should confirm that the \texttt{read-number} word works correctly.%
\footnote{There is the possibility of an invalid number being entered at the
keyboard. In this case, \texttt{parse-number} returns \texttt{f},
the boolean false value. For the sake of simplicity, we ignore this
case in the numbers game example. However, proper error handling is
an essential part of any large program and is covered later.%
}
\subsection{Printing some messages}
Now we need to make some words for printing various messages. They
are given here without further ado:
\begin{alltt}
: guess-banner
"I'm thinking of a number between 0 and 100." print ;
: guess-prompt "Enter your guess: " write ;
: too-high "Too high" print ;
: too-low "Too low" print ;
: correct "Correct - you win!" print ;
\end{alltt}
Note that in the above, stack effect comments are omitted, since they
are obvious from context. You should ensure the words work correctly
after loading the source file into the interpreter.
\subsection{Taking action based on a guess}
The next logical step is to write a word \texttt{judge-guess} that
takes the user's guess along with the actual number to be guessed,
and prints one of the messages \texttt{too-high}, \texttt{too-low},
or \texttt{correct}. This word will also push a boolean flag, indicating
if the game should continue or not -- in the case of a correct guess,
the game does not continue.
This description of judge-guess is a mouthful -- and it suggests that
it may be best to split it into two words. The first word we write
handles the more specific case of an \emph{inexact} guess -- so it
prints either \texttt{too-low} or \texttt{too-high}.
\begin{alltt}
: inexact-guess ( actual guess -{}- )
< {[} too-high {]} {[} too-low {]} ifte ;
\end{alltt}
Note that the word gives incorrect output if the two parameters are
equal. However, it will never be called this way.
With this out of the way, the implementation of judge-guess is an
easy task to tackle. Using the words \texttt{inexact-guess}, \texttt{2dup}, \texttt{2drop} and \texttt{=}, we can write:
\begin{alltt}
: judge-guess ( actual guess -{}- ? )
2dup = {[}
2drop correct f
{]} {[}
inexact-guess t
{]} ifte ;
\end{alltt}
The word \texttt{=} is found in the \texttt{kernel} vocabulary, and the words \texttt{2dup} and \texttt{2drop} are found in the \texttt{stack} vocabulary. Since \texttt{=}
consumes both its inputs, we must first duplicate the \texttt{actual} and \texttt{guess} parameters using \texttt{2dup}. The word \texttt{correct} does not need to do anything with these two numbers, so they are popped off the stack using \texttt{2drop}. Try evaluating the following
in the interpreter to see what's going on:
\begin{alltt}
clear 1 2 2dup = .s
\emph{\{ 1 2 f \}}
clear 4 4 2dup = .s
\emph{\{ 4 4 t \}}
\end{alltt}
Test \texttt{judge-guess} with a few inputs:
\begin{alltt}
1 10 judge-guess .
\emph{Too low}
\emph{t}
89 43 judge-guess .
\emph{Too high}
\emph{t}
64 64 judge-guess .
\emph{Correct}
\emph{f}
\end{alltt}
\subsection{Generating random numbers}
The \texttt{random-int} word \texttt{( min max -{}- n )} pushes a
random number in a specified range. The range is inclusive, so both
the minimum and maximum indexes are candidate random numbers. Use
\texttt{apropos.} to determine that this word is in the \texttt{random}
vocabulary. For the purposes of this game, random numbers will be
in the range of 0 to 100, so we can define a word that generates a
random number in the range of 0 to 100:
\begin{alltt}
: number-to-guess ( -{}- n ) 0 100 random-int ;
\end{alltt}
Add the word definition to the source file, along with the appropriate
\texttt{USING:} declaration. Load the source file in the interpreter,
and confirm that the word functions correctly, and that its stack
effect comment is accurate.
\subsection{The game loop}
The game loop consists of repeated calls to \texttt{guess-prompt},
\texttt{read-number} and \texttt{judge-guess}. If \texttt{judge-guess}
returns \texttt{f}, the loop stops, otherwise it continues. This is
realized with a recursive implementation:
\begin{alltt}
: numbers-game-loop ( actual -{}- )
dup guess-prompt read-number judge-guess {[}
numbers-game-loop
{]} {[}
drop
{]} ifte ;
\end{alltt}
In Factor, tail-recursive words consume a bounded amount of call stack
space. This means you are free to pick recursion or iteration based
on their own merits when solving a problem. In many other languages,
the usefulness of recursion is severely limited by the lack of tail-recursive
call optimization.
\subsection{Finishing off}
The last task is to combine everything into the main \texttt{numbers-game}
word. This is easier than it seems:
\begin{alltt}
: numbers-game number-to-guess numbers-game-loop ;
\end{alltt}
Try it out! Simply invoke the \texttt{numbers-game} word in the interpreter.
It should work flawlessly, assuming you tested each component of this
design incrementally!
\subsection{The complete program}
\begin{verbatim}
! Numbers game example
IN: numbers-game
USING: kernel math parser random stdio ;
: read-number ( -- n ) read parse-number ;
: guess-banner
"I'm thinking of a number between 0 and 100." print ;
: guess-prompt "Enter your guess: " write ;
: too-high "Too high" print ;
: too-low "Too low" print ;
: correct "Correct - you win!" print ;
: inexact-guess ( actual guess -- )
< [ too-high ] [ too-low ] ifte ;
: judge-guess ( actual guess -- ? )
2dup = [
2drop correct f
] [
inexact-guess t
] ifte ;
: number-to-guess ( -- n ) 0 100 random-int ;
: numbers-game-loop ( actual -- )
dup guess-prompt read-number judge-guess [
numbers-game-loop
] [
drop
] ifte ;
: numbers-game number-to-guess numbers-game-loop ;
\end{verbatim}
\chapter{Language reference}
\section{Conventions}
When examples of interpreter interactions are given in this guide, the input is in a roman font, and any
@ -87,6 +346,9 @@ output from the interpreter is in boldface:
\textbf{ok} "Hello, world!" print
\textbf{Hello, world!}
\end{alltt}
\subsection{Word definitions}
Parsing words, defined in \ref{parser}, are presented with the following notation.
\wordtable{
\vocabulary{foo}
@ -174,6 +436,18 @@ The following naming conventions are used in the Factor library.
\item[\texttt{make-foo}] executes a quotation in a namespace where a sequence of type \texttt{foo} is being constructed; for example, \texttt{make-string}
\end{description}
\subsection{Mathematics}
This guide uses the standard mathematical notation to denote intervals (ranges of numbers).
\begin{tabular}{l|l}
Notation&Meaning\\
$(a,b)$&All numbers from $a$ to $b$, excluding $a$ and $b$\\
$[a,b)$&All numbers from $a$ to $b$, including $a$ and excluding and $b$\\
$(a,b]$&All numbers from $a$ to $b$, excluding $a$ and including and $b$\\
$[a,b]$&All numbers from $a$ to $b$, including $a$ and $b$
\end{tabular}
\section{Syntax}
\newcommand{\parseglos}{\glossary{name=parser,
description={a set of words in the \texttt{parser} vocabulary, primarily \texttt{parse}, \texttt{eval}, \texttt{parse-file} and \texttt{run-file}, that creates objects from their printed representations, and adds word definitions to the dictionary}}}
@ -1741,7 +2015,7 @@ Factor uses delegation is used instead of inheritance, but it is not a direct
substitute; in particular, the semantics differ in that a delegated
method call receives the delegate on the stack, not the original object.
\chapter{The library}
\chapter{Library reference}
\section{Sequences}
@ -2052,12 +2326,12 @@ Lists of values are represented with nested cons cells. The car is the first ele
The following example demonstrates the construction of lists as chains of cons cells, along with the literal syntax used to print lists:
\begin{alltt}
\textbf{ok} {[} 1 2 3 4 {]} car .
\textbf{ok} {[} 1 2 3 {]} car .
\textbf{1}
\textbf{ok} {[} 1 2 3 4 {]} cdr .
\textbf{{[} 2 3 4 {]}}
\textbf{ok} {[} 1 2 3 4 {]} cdr cdr .
\textbf{{[} 3 4 {]}}
\textbf{ok} {[} 1 2 3 {]} cdr .
\textbf{{[} 2 3 {]}}
\textbf{ok} {[} 1 2 3 {]} cdr cdr .
\textbf{{[} 3 {]}}
\end{alltt}
\begin{figure}
@ -2990,6 +3264,14 @@ BIN: 11111 -2 shift .b
\emph{111}
\end{alltt}
\subsubsection{Generating random numbers}
\wordtable{
\vocabulary{math}
\ordinaryword{random-int}{random-int ( min max -- n )}
}
Outputs a pseudo-random integer in the interval $[min,max]$.
\subsection{\label{ratios}Rational numbers}
\newcommand{\rationalglos}{\glossary{
@ -3134,8 +3416,6 @@ Converts between complex numbers and pairs of real numbers representing them in
\wordtable{
\vocabulary{math}
\ordinaryword{abs}{abs ( n -- r )}
\\
\vocabulary{math}
\ordinaryword{arg}{arg ( n -- theta )}
}
@ -3192,6 +3472,22 @@ Secant&\texttt{sec}&\texttt{sech}&\texttt{asec}&\texttt{asech}\\
Cotangent&\texttt{cot}&\texttt{coth}&\texttt{acot}&\texttt{acoth}
\end{tabular}
\subsection{Constants}
The following words in the \texttt{math} vocabulary push constant values on the stack.
\begin{tabular}{l|l}
Word&Value\\
\hline
\texttt{i}&Positive imaginary unit -- \texttt{\pound\tto 0 1 \ttc\pound}\\
\texttt{-i}&Negative imaginary unit -- \texttt{\pound\tto 0 -1 \ttc\pound}\\
\texttt{inf}&Positive floating point infinity\\
\texttt{-inf}&Negative floating point infinity\\
\texttt{e}&Base of natural logarithm ($e\approx 2.7182818284590452354$)\\
\texttt{pi}&Ratio of circumference to diameter ($\pi\approx 3.14159265358979323846$)\\
\texttt{pi/2}&$\frac{\pi}{2}\approx 1.5707963267948966$
\end{tabular}
\section{Streams}
\glossary{name=stream,
description={a source or sink of characters supporting some subset of the stream protocol, used as an end-point for input/output operations}}
@ -3245,7 +3541,7 @@ The following three words are optional, and should be implemented on output stre
}
Outputs a character or string to the stream. This might not result in immediate output to the underlying resource if the stream performs buffering, like all file and network streams do.
The \texttt{attrs} parameter is an association list holding style information, and it is ignored by most streams -- one exception is HTML streams, documented in \ref{html}. Formatted output is a relatively rare case so most of the time either the \texttt{stream-write} or \texttt{stream-print} word is used. They are described in the next section.
The \texttt{attrs} parameter is an association list holding style information, and it is ignored by most streams -- one exception is HTML streams (\ref{html}). Most of the time either the \texttt{stream-write} or \texttt{stream-print} word is used. They are described in the next section.
\wordtable{
\vocabulary{streams}
@ -3443,35 +3739,30 @@ Outputs a list of file system attributes, or \texttt{f} if the file does not exi
\subsection{TCP/IP networking}
\wordtable{
\vocabulary{files}
\vocabulary{streams}
\ordinaryword{<client>}{<client>~( host port -- stream~)}
}
Connects to TCP/IP port number \texttt{port} on the host named by \texttt{host}, and returns a bidirectional stream. An exception is thrown if the connection attempt fails.
\wordtable{
\vocabulary{files}
\vocabulary{streams}
\ordinaryword{<server>}{<server>~( port -- server~)}
}
Begins listening for connections to \texttt{port} on all network interfaces. An exception is thrown if the port cannot be opened. The returned object can be used as an input to the \texttt{stream-close} and \texttt{accept} words.
\wordtable{
\vocabulary{files}
\vocabulary{streams}
\ordinaryword{accept}{accept~( server -- stream~)}
}
Waits for a connection to the port number that \texttt{server} is listening on, and outputs a bidirectional stream when the connection has been established. An exception is thrown if an error occurs.
\wordtable{
\vocabulary{files}
\vocabulary{streams}
\ordinaryword{client-stream-host}{client-stream-host~( stream -- port~)}
\ordinaryword{client-stream-port}{client-stream-port~( stream -- port~)}
}
Outputs the local port number that the client stream is connected to. Only useful for streams returned by \texttt{accept}.
\wordtable{
\vocabulary{files}
\ordinaryword{client-stream-port}{client-stream-port~( stream -- port~)}
}
Outputs the IP address of the client as a dotted-quad string. Only useful for streams returned by \texttt{accept}.
Outputs the IP address as a dotted-quad string, and the local port number, respectively, of a client socket returned from \texttt{accept}.
\subsection{Special streams}
@ -3492,6 +3783,11 @@ Creates a duplex stream. Writing to a duplex stream will write to \texttt{out},
\subsection{Printing objects}
\glossary{name=prettyprinter,
description={a set of words for printing objects in readable form}}
One of Factor's key features is the ability to print almost any object in a readable form. This greatly aids debugging and provides the building blocks for light-weight object serialization facilities.
\glossary{
name=unreadable string,
description={a string which raises a parse error when parsed}}
@ -3519,7 +3815,7 @@ string
\ordinaryword{prettyprint}{prettyprint~( object --~)}
}
Prints the object using literal syntax that can be parsed back again. This is not a general serialization mechanism; the following restrictions apply:
Prints the object using literal syntax that can be parsed back again. While the prettyprinter supports more classes of objects than \texttt{unparse}, it is still not a general serialization mechanism. The following restrictions apply:
\begin{itemize}
\item Not all objects print in a readable way. Namely, the following classes do not:
@ -3542,7 +3838,7 @@ Prettyprint the object, except all output is on a single line without indentatio
\ordinaryword{[.]}{[.]~( sequence --~)}
}
Prettyprint each element of the sequence on its own line using \texttt{.}.
Prettyprint each element of the sequence on its own line using the \texttt{.} word.
\subsubsection{Variables controlling the prettyprinter}
@ -3552,7 +3848,7 @@ The following variables affect the prettyprinter if set in the dynamic scope fro
\vocabulary{prettyprint}
\symbolword{tab-size}
}
Controls the indentation for nested structure such as lists, vectors, hashtables and tuples. The default tab size is 4.
Specifies the indentation for recursive objects such as lists, vectors, hashtables and tuples. The default tab size is 4.
\wordtable{
\vocabulary{prettyprint}
@ -3568,7 +3864,12 @@ If set to true, the prettyprinter does not emit newlines. The default is \texttt
\subsubsection{Extending the prettyprinter}
If define your own data type and wish to add new syntax for it, extending the prettyprinter is one half of the work. The other half is writing parsing words (\ref{parsing-words}).
If define your own data type and wish to add new syntax for it, you must implement two facilities:
\begin{itemize}
\item Parsing word(s) for reading your data type,
\item A prettyprinter method for printing your data type.
\end{itemize}
Parsing words are documented in \ref{parsing-words}.
\wordtable{
\vocabulary{prettyprint}
@ -3576,7 +3877,7 @@ If define your own data type and wish to add new syntax for it, extending the pr
}
Prettyprints the given object. Unlike \texttt{prettyprint*}, this word does not emit a trailing newline, and the current indent level is given. This word is also generic, so you can add methods to have it print your own data types in a nice way.
The remaining words in this section are useful in the implementation of \texttt{prettyprint*} methods.
The remaining words in this section are useful in the implementation of prettyprinter methods.
\wordtable{
\vocabulary{prettyprint}
\genericword{word.}{word.~( word -- )}
@ -3611,6 +3912,9 @@ Decreases the indent level and emits a newline if \texttt{one-line} is off.
\section{Web framework}
\subsection{HTTP client}
\subsection{\label{html}HTML output}
HTML streams output text using the stream APIs, and escape special characters as HTML entities. Additionally, HTML streams implement the \texttt{stream-write-attr} word to support output of various HTML tags.
@ -3656,7 +3960,7 @@ Hyperlinks to files and words point to the file and browser responders, respecti
\section{C library interface}
\chapter{The development environment}
\chapter{Development tools}
Factor supports interactive development in a live environment. Instead of working with
static executable files and restarting your application after each change, you can
@ -3664,7 +3968,7 @@ incrementally make changes to your application and test them immediately. If you
notice an undesirable behavior, Factor's powerful reflection features will aid in
pinpointing the error.
If you are used to a statically typed language, you might find Factor's tendency to only fail at runtime hard to work with at first. However, the interactive development tools outlined in this document allow a much quicker turn-around time for testing changes. Also, write unit tests -- unit testing is a great way to ensure that old bugs do not re-appear once they've been fixed.
If you are used to a statically typed language, you might find Factor's tendency to only fail at runtime hard to work with at first. However, the interactive development tools outlined in this chapter allow a much quicker turn-around time for testing changes. Also, write unit tests -- unit testing is a great way to ensure that old bugs do not re-appear once they've been fixed.
\section{System organization}

View File

@ -16,6 +16,8 @@ USE: namespaces
#! Returns a random element from the given list.
dup >r length 1 - 0 swap random-int r> nth ;
: random-boolean ( -- ? ) 0 1 random-int 0 = ;
: random-subset ( list -- list )
#! Returns a random subset of the given list. Each item is
#! chosen with a 50%

View File

@ -44,9 +44,9 @@ t [
"/library/math/pow.factor"
"/library/math/trig-hyp.factor"
"/library/math/arc-trig-hyp.factor"
"/library/math/random.factor"
"/library/in-thread.factor"
"/library/random.factor"
"/library/io/directories.factor"
"/library/io/stdio-binary.factor"

View File

@ -4,7 +4,7 @@ IN: image
USING: kernel lists math memory namespaces parser words vectors
hashtables generic alien assembler compiler errors files generic
io-internals kernel kernel-internals lists math math-internals
parser profiler random strings unparser vectors words
parser profiler strings unparser vectors words
hashtables ;
! This symbol needs the same hashcode in the target as in the
@ -147,8 +147,8 @@ vocabularies get [
[ "room" "memory" [ [ ] [ integer integer integer integer ] ] ]
[ "os-env" "kernel" [ [ string ] [ object ] ] ]
[ "millis" "kernel" [ [ ] [ integer ] ] ]
[ "init-random" "random" [ [ ] [ ] ] ]
[ "(random-int)" "random" [ [ ] [ integer ] ] ]
[ "init-random" "math" [ [ ] [ ] ] ]
[ "(random-int)" "math" [ [ ] [ integer ] ] ]
[ "type" "kernel" [ [ object ] [ fixnum ] ] ]
[ "cwd" "files" [ [ ] [ string ] ] ]
[ "cd" "files" [ [ string ] [ ] ] ]

View File

@ -40,7 +40,7 @@ SYMBOL: post-refresh-get?
: get-random-id ( -- id )
#! Generate a random id to use for continuation URL's
[ 32 [ random-digit unparse , ] times ] make-string str>number 36 >base ;
[ 32 [ 0 9 random-int unparse , ] times ] make-string str>number 36 >base ;
#! Name of variable holding the table of continuations.
SYMBOL: table

View File

@ -1,6 +1,6 @@
! Copyright (C) 2003, 2005 Slava Pestov.
! See http://factor.sf.net/license.txt for BSD license.
IN: random USING: kernel lists math ;
IN: math USING: kernel ;
: power-of-2? ( n -- ? ) dup dup neg bitand = ;
@ -19,5 +19,3 @@ IN: random USING: kernel lists math ;
] ifte ;
: random-int ( min max -- n ) dupd swap - random-int-0 + ;
: random-boolean ( -- ? ) 0 1 random-int 0 = ;
: random-digit ( -- digit ) 0 9 random-int ;