text:
Write Yourself a Scheme in 48 Hours/Evaluation, Part 1

Beginning the Evaluator
Currently, we've just been printing out whether or not we recognize the given program fragment. We're about to take the first steps towards a working Scheme interpreter: assigning values to program fragments. We'll be starting with baby steps, but fairly soon you'll be progressing to working with computations.

Let's start by telling Haskell how to print out a string representation of the various possible s:

This is our first real introduction to pattern matching. Pattern matching is a way of destructuring an algebraic data type, selecting a code clause based on its constructor and then binding the components to variables. Any constructor can appear in a pattern; that pattern matches a value if the tag is the same as the value's tag and all subpatterns match their corresponding components. Patterns can be nested arbitrarily deep, with matching proceeding in an inside → outside, left → right order. The clauses of a function definition are tried in textual order, until one of the patterns matches. If this is confusing, you'll see some examples of deeply-nested patterns when we get further into the evaluator.

For now, you only need to know that each clause of the above definition matches one of the constructors of, and the right-hand side tells what to do for a value of that constructor.

The  and   clauses work similarly, but we need to define a helper function   to convert the contained list into a string:

The  function works like the Haskell Prelude's  function, which glues together a list of words with spaces. Since we're dealing with a list of s instead of words, we define a function that first converts the  s into their string representations and then applies   to it:

Our definition of unwordsList doesn't include any arguments. This is an example of point-free style: writing definitions purely in terms of function composition and partial application, without regard to individual values or "points". Instead, we define it as the composition of a couple of built-in functions. First, we partially-apply to , which creates a function that takes a list of  s and returns a list of their string representations. Haskell functions are curried: this means that a function of two arguments, like, is really a function that returns a function of one argument. As a result, if you supply only a single argument, you get back a function of one argument that you can pass around, compose, and apply later. In this case, we compose it with unwords:  converts a list of  s to a list of their string representations, and then   joins the result together with spaces.

We used the function above. This standard Haskell function lets you convert any type that's an instance of the class  into a string. We'd like to be able to do the same with, so we make it into a member of the class  , defining its   method as  :

A full treatment of type classes is beyond the scope of this tutorial; you can find more information in other tutorials and the Haskell 2010 report.

Let's try things out by changing our readExpr function so it returns the string representation of the value actually parsed, instead of just "Found value":

And compile and run…

$ ghc -package parsec -o parser listing4.1.hs $ ./parser "(1 2 2)" Found (1 2 2) $ ./parser "'(1 3 (\"this\" \"one\"))" Found (quote (1 3 ("this" "one")))

Beginnings of an evaluator: Primitives
Now, we start with the beginnings of an evaluator. The purpose of an evaluator is to map some "code" data type into some "data" data type, the result of the evaluation. In Lisp, the data types for both code and data are the same, so our evaluator will return a. Other languages often have more complicated code structures, with a variety of syntactic forms.

Evaluating numbers, strings, booleans, and quoted lists is fairly simple: return the datum itself.

This introduces a new type of pattern. The notation  matches against any   that's a string and then binds   to the whole , and not just the contents of the   constructor. The result has type  instead of type. The underbar is the "don't care" variable, matching any value yet not binding it to a variable. It can be used in any pattern, but is especially useful with @-patterns (where you bind the variable to the whole pattern) and with simple constructor-tests where you're just interested in the tag of the constructor.

The last clause is our first introduction to nested patterns. The type of data contained by  is , a list of  s. We match that against the specific two-element list  , a list where the first element is the symbol "quote" and the second element can be anything. Then we return that second element.

Let's integrate  into our existing code. Start by changing  back so it returns the expression instead of a string representation of the expression:

And then change our main function to read an expression, evaluate it, convert it to a string, and print it out. Now that we know about the  monad sequencing operator and the function composition operator, let's use them to make this a bit more concise:

Here, we take the result of the  action (a list of strings) and pass it into the composition of:

 * 1) take the first value ;
 * 2) parse it ;
 * 3) evaluate it ;
 * 4) convert it to a string and print it.

Compile and run the code the normal way:

$ ghc -package parsec -o eval listing4.2.hs $ ./eval "'atom" atom $ ./eval 2 2 $ ./eval "\"a string\"" "a string" $ ./eval "(+ 2 2)" Fail: listing6.hs:83: Non-exhaustive patterns in function eval

We still can't do all that much useful with the program (witness the failed  call), but the basic skeleton is in place. Soon, we'll be extending it with some functions to make it useful.

Adding basic primitives
Next, we'll improve our Scheme so we can use it as a simple calculator. It's still not yet a "programming language", but it's getting close.

Begin by adding a clause to eval to handle function application. Remember that all clauses of a function definition must be placed together and are evaluated in textual order, so this should go after the other eval clauses:

This is another nested pattern, but this time we match against the cons operator ":" instead of a literal list. Lists in Haskell are really syntactic sugar for a chain of cons applications and the empty list:. By pattern-matching against cons itself instead of a literal list, we're saying "give me the rest of the list" instead of "give me the second element of the list". For example, if we passed  to eval,   would be bound to "+" and   would be bound to.

The rest of the clause consists of a couple of functions we've seen before and one we haven't defined yet. We have to recursively evaluate each argument, so we map  over the args. This is what lets us write compound expressions like. Then we take the resulting list of evaluated arguments, and pass it and the original function to apply:

The built-in function looks up a key (its first argument) in a list of pairs. However, lookup will fail if no pair in the list contains the matching key. To express this, it returns an instance of the built-in type. We use the function to specify what to do in case of either success or failure. If the function isn't found, we return a  value, equivalent to   (we'll add more robust error-checking later). If it is found, we apply it to the arguments using, an operator section of the function application operator.

Next, we define the list of primitives that we support:

Look at the type of. It is a list of pairs, just like  expects, but the values of the pairs are functions from   to  . In Haskell, you can easily store functions in other data structures, though the functions must all have the same type.

Also, the functions that we store are themselves the result of a function,, which we haven't defined yet. This takes a primitive Haskell function (often an operator section) and wraps it with code to unpack an argument list, apply the function to it, and wrap the result up in our  constructor.

As with R5RS Scheme, we don't limit ourselves to only two arguments. Our numeric operations can work on a list of any length, so, and. We use the built-in function to do this. It essentially changes every cons operator in the list to the binary function we supply,.

Unlike R5RS Scheme, we're implementing a form of weak typing. That means that if a value can be interpreted as a number (like the string "2"), we'll use it as one, even if it's tagged as a string. We do this by adding a couple extra clauses to. If we're unpacking a string, attempt to parse it with Haskell's built-in function, which returns a list of pairs of (parsed value, remaining string).

For lists, we pattern-match against the one-element list and try to unpack that. Anything else falls through to the next case.

If we can't parse the number, for any reason, we'll return 0 for now. We'll fix this shortly so that it signals an error.

Compile and run this the normal way. Note how we get nested expressions "for free" because we call eval on each of the arguments of a function:

$ ghc -package parsec -o eval listing7.hs $ ./eval "(+ 2 2)" 4 $ ./eval "(+ 2 (-4 1))" 2 $ ./eval "(+ 2 (- 4 1))" 5 $ ./eval "(- (+ 4 6 3) 3 5 2)" 3


text:
Write Yourself a Scheme in 48 Hours/Error Checking and Exceptions

Currently, there are a variety of places within the code where we either ignore errors or silently assign "default" values like  or 0 that make no sense. Some languages – like Perl and PHP – get along fine with this approach. However, it often means that errors pass silently throughout the program until they become big problems, which means rather inconvenient debugging sessions for the programmer. We'd like to signal errors as soon as they happen and immediately break out of execution.

First, we need to import  to get access to Haskell's built-in error functions:

On Debian based systems this needs  installed.

Then, we should define a data type to represent an error:

This is a few more constructors than we need at the moment, but we might as well foresee all the other things that can go wrong in the interpreter later. Next, we define how to print out the various types of errors and make  an instance of  :

Then we define a type to represent functions that may throw a  or return a value. Remember how used an  data type to represent exceptions? We take the same approach here:

Type constructors are curried just like functions, and can also be partially applied. A full type would be  or , but we want to say   and so on. We only partially apply  to , creating a type constructor   that we can use on any data type.

is yet another instance of a monad. In this case, the "extra information" being passed between  actions is whether or not an error occurred. Bind applies its function if the  action holds a normal value, or passes an error straight through without computation. This is how exceptions work in other languages, but because Haskell is lazily-evaluated, there's no need for a separate control-flow construct. If bind determines that a value is already an error, the function is never called.

The  library automatically gives the   monad two other functions besides the standard monadic ones:

 * 1), which takes an   value and lifts it into the   (error) constructor of an
 * 2), which takes an   action and a function that turns an error into another   action. If the action represents an error, it applies the function, which you can use to, e.g. turn the error value into a normal one via   or re-throw as a different error.

In our program, we'll be converting all of our errors to their string representations and returning that as a normal value. Let's create a helper function to do that for us:

The result of calling  is another   action which will always have valid  data. We still need to extract that data from the  monad so it can be passed around to other functions:

We purposely leave  undefined for a   constructor, because that represents a programmer error. We intend to use  only after a , so it's better to fail fast than to inject bad values into the rest of the program.

Now that we have all the basic infrastructure, it's time to start using our error-handling functions. Remember how our parser had previously just returned a string saying "No match" on an error? Let's change it so that it wraps and throws the original :

Here, we first wrap the original  with the   constructor , and then use the built-in function  to return that in our   monad. Since  now returns a monadic value, we also need to wrap the other case in a return function.

Next, we change the type signature of  to return a monadic value, adjust the return values accordingly, and add a clause to throw an error if we encounter a pattern that we don't recognize:

Since the function application clause calls  (which now returns a monadic value) recursively, we need to change that clause. First, we had to change  to, which maps a monadic function over a list of values, sequences the resulting actions together with bind, and then returns a list of the inner results. Inside the  monad, this sequencing performs all computations sequentially but throws an error value if any one of them fails – giving you   on success, or   on failure. Then, we used the monadic "bind" operation to pass the result into the partially applied "apply func", again returning an error if either operation failed.

Next, we change  itself so that it throws an error if it doesn't recognize the function:

We didn't add a return statement to the function application. We're about to change the type of our primitives, so that the function returned from the lookup itself returns a  action:

And, of course, we need to change the numericBinop function that implements these primitives so it throws an error if there's only one argument:

We use an at-pattern to capture the single-value case because we want to include the actual value passed in for error-reporting purposes. Here, we're looking for a list of exactly one element, and we don't care what that element is. We also need to use  to sequence the results of , because each individual call to   may fail with a  :

Finally, we need to change our main function to use this whole big error monad. This can get a little complicated, because now we're dealing with two monads ( (for errors) and  ). As a result, we go back to do-notation, because it's nearly impossible to use point-free style when the result of one monad is nested inside another:

Here's what this new function is doing:

 * 1)   is the list of command-line arguments.
 * 2)   is the result of:
 * 3) taking first argument ;
 * 4) parsing it ;
 * 5) passing it to   (the bind operation has higher precedence than  );
 * 6) calling   on it within the   monad. (Note also that the whole action has type , giving   type  . It has to be, because our   function can only convert errors to  s, and that type must match the type of normal values.)
 * 7) Caught is the result of:
 * 8) calling   on , converting errors to their string representation;
 * 9) calling   to get a   out of this   action;
 * 10) printing the results through.

Compile and run the new code, and try throwing it a couple errors:

$ ghc -package parsec -o errorcheck [../code/listing5.hs listing5.hs] $ ./errorcheck "(+ 2 \"two\")" Invalid type: expected number, found "two" $ ./errorcheck "(+ 2)" Expected 2 args; found values 2 $ ./errorcheck "(what? 2)" Unrecognized primitive function args: "what?"

Some readers have reported that you need to add a  flag to build this example, and presumably all further listings. This tells GHC to build a complete executable, searching out all dependencies listed in the import statements. The command above works on my system, but if it fails on yours, give  a try.

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Write Yourself a Scheme in 48 Hours/Evaluation, Part 2

Additional Primitives: Partial Application
Now that we can deal with type errors, bad arguments, and so on, we'll flesh out our primitive list so that it does something more than calculate. We'll add boolean operators, conditionals, and some basic string operations.

Start by adding the following into the list of primitives:

These depend on helper functions that we haven't written yet:,   and. Instead of taking a variable number of arguments and returning an integer, these both take exactly two arguments and return a boolean. They differ from each other only in the type of argument they expect, so let's factor the duplication into a generic  function that's parametrized by the unpacker function it applies to its arguments:

Because each argument may throw a type mismatch, we have to unpack them sequentially, in a do-block (for the  monad). We then apply the operation to the two arguments and wrap the result in the  constructor. Any function can be turned into an infix operator by wrapping it in backticks.

Also, take a look at the type signature. takes two functions as its first two arguments: the first is used to unpack the arguments from s to native Haskell types, and the second is the actual operation to perform. By parameterizing different parts of the behavior, you make the function more reusable.

Now we define three functions that specialize  with different unpackers:

We haven't told Haskell how to unpack strings from s yet. This works similarly to, pattern matching against the value and either returning it or throwing an error. Again, if passed a primitive value that could be interpreted as a string (such as a number or boolean), it will silently convert it to the string representation.

And we use similar code to unpack booleans:

Let's compile and test this to make sure it's working, before we proceed to the next feature:

$ ghc -package parsec -o simple_parser [../code/listing6.1.hs listing6.1.hs] $ ./simple_parser "(< 2 3)" #t $ ./simple_parser "(> 2 3)" #f $ ./simple_parser "(>= 3 3)" #t $ ./simple_parser "(string=? \"test\" \"test\")" #t $ ./simple_parser "(string<? \"abc\" \"bba\")" #t

Conditionals: Pattern Matching 2
Now, we'll proceed to adding an if-clause to our evaluator. As with standard Scheme, our evaluator considers  to be false and any other value to be true:

As the function definitions are evaluated in order, be sure to place this one above  or it will throw a   error.

This is another example of nested pattern-matching. Here, we're looking for a 4-element list. The first element must be the atom. The others can be any Scheme forms. We take the first element, evaluate, and if it's false, evaluate the alternative. Otherwise, we evaluate the consequent.

Compile and run this, and you'll be able to play around with conditionals:

$ ghc -package parsec -o simple_parser [../code/listing6.2.hs listing6.2.hs] $ ./simple_parser "(if (> 2 3) \"no\" \"yes\")" "yes" $ ./simple_parser "(if (= 3 3) (+ 2 3 (- 5 1)) \"unequal\")" 9

List Primitives:,, and
For good measure, let's also add in the basic list-handling primitives. Because we've chosen to represent our lists as Haskell algebraic data types instead of pairs, these are somewhat more complicated than their definitions in many Lisps. It's easiest to think of them in terms of their effect on printed S-expressions:

 * 1)   – not a list
 * 2)   –   only takes one argument
 * 1)   – not a list
 * 2)   –   only takes one argument
 * 1)   –   only takes one argument

We can translate these fairly straightforwardly into pattern clauses, recalling that  divides a list into the first element and the rest:

Let's do the same with cdr:

 * 1)   – not a list
 * 2)   – too many arguments
 * 1)   – not a list
 * 2)   – too many arguments
 * 1)   – not a list
 * 2)   – too many arguments
 * 1)   – too many arguments

We can represent the first three cases with a single clause. Our parser represents  as , and when you pattern-match   against  ,   is bound to. The other ones translate to separate clauses:

is a little tricky, enough that we should go through each clause case-by-case. If you cons together anything with, you end up with a one-item list, the   serving as a terminator:

If you  together anything and a list, it's like tacking that anything onto the front of the list:

However, if the list is a, then it should stay a  , taking into account the improper tail:

If you  together two non-lists, or put a list in front, you get a. This is because such a  cell isn't terminated by the normal   that most lists are.

Finally, attempting to  together more or less than two arguments is an error:

Our last step is to implement. Scheme offers three levels of equivalence predicates:, , and. For our purposes,  and   are basically the same: they recognize two items as the same if they print the same, and are fairly slow. So we can write one function for both of them and register it under  and.

Most of these clauses are self-explanatory, the exception being the one for two. This, after checking to make sure the lists are the same length, s the two lists of pairs, and then uses the function to return   if   returns   on any of the pairs. is an example of a local definition: it is defined using the  keyword, just like a normal function, but is available only within that particular clause of. Since we know that  only throws an error if the number of arguments is not 2, the line   will never be executed at the moment.

and Weak Typing: Heterogenous Lists
Since we introduced weak typing above, we'd also like to introduce an  function that ignores differences in the type tags and only tests if two values can be interpreted the same. For example,, yet we'd like. Basically, we want to try all of our unpack functions, and if any of them result in Haskell values that are equal, return.

The obvious way to approach this is to store the unpacking functions in a list and use  to execute them in turn. Unfortunately, this doesn't work, because standard Haskell only lets you put objects in a list if they're the same type. The various unpacker functions return different types, so you can't store them in the same list.

We'll get around this by using a GHC extension – Existential Types – that lets us create a heterogenous list, subject to typeclass constraints. Extensions are fairly common in the Haskell world: they're basically necessary to create any reasonably large program, and they're often compatible between implementations (existential types work in both Hugs and GHC and are a candidate for standardization). Note you need to use a special compiler flag for this:  as mentioned below; the newer  ; or add the pragma   to the beginning of your code (In general, the compiler flag   can be replaced by the pragma   inside the source file).

The first thing we need to do is define a data type that can hold any function from a, provided that that   supports equality:

This is like any normal algebraic datatype, except for the type constraint. It says, "For any type that is an instance of, you can define an   that takes a function from   to that type, and may throw an error". We'll have to wrap our functions with the  constructor, but then we can create a list of  s that does just what we want it.

Rather than jump straight to the  function, let's first define a helper function that takes an   and then determines if two  s are equal when it unpacks them:

After pattern-matching to retrieve the actual function, we enter a do-block for the  monad. This retrieves the Haskell values of the two s, and then tests whether they're equal. If there is an error anywhere within the two unpackers, it returns, using the  function because  expects a function to apply to the error value.

Finally, we can define  in terms of these helpers:

The first action makes a heterogenous list of, and then maps the partially applied   over it. This gives a list of booleans, so we use the Prelude function to return true if any single one of them is true.

The second action tests the two arguments with. Since we want  to be looser than , it should return true whenever   does so. This also lets us avoid handling cases like the list or dotted-list (though this introduces a bug; see exercise #2 in this section).

Finally,   s both of these values together and wraps the result in the   constructor, returning a. The  is a quick way of extracting a value from an algebraic type: it pattern matches   against the   value, and then returns. The result of a let-expression is the expression following the keyword.

To use these functions, insert them into our primitives list:

To compile this code, you need to enable GHC extensions with :

$ ghc -package parsec -fglasgow-exts -o parser [../code/listing6.4.hs listing6.4.hs] $ ./parser "(cdr '(a simple test))" (simple test) $ ./parser "(car (cdr '(a simple test)))" simple $ ./parser "(car '((this is) a test))" (this is) $ ./parser "(cons '(this is) 'test)" ((this is) . test) $ ./parser "(cons '(this is) ')" ((this is)) $ ./parser "(eqv? 1 3)" #f $ ./parser "(eqv? 3 3)" #t $ ./parser "(eqv? 'atom 'atom)" #t


text:
Write Yourself a Scheme in 48 Hours/Building a REPL

So far, we've been content to evaluate single expressions from the command line, printing the result and exiting afterwards. This is fine for a calculator, but isn't what most people think of as "programming". We'd like to be able to define new functions and variables, and refer to them later. But before we can do this, we need to build a system that can execute multiple statements without exiting the program.

Instead of executing a whole program at once, we're going to build a read-eval-print loop. This reads in expressions from the console one at a time and executes them interactively, printing the result after each expression. Later expressions can reference variables set by earlier ones (or will be able to, after the next section), letting you build up libraries of functions.

First, we need to import some additional IO functions. Add the following to the top of the program:

Next, we define a couple of helper functions to simplify some of our IO tasks. We'll want a function that prints out a string and immediately flushes the stream; otherwise, output might sit in output buffers and the user will never see prompts or results.

Then, we create a function that prints out a prompt and reads in a line of input:

Pull the code to parse and evaluate a string and trap the errors out of main into its own function:

And write a function that evaluates a string and prints the result:

Now it's time to tie it all together. We want to read input, perform a function, and print the output, all in an infinite loop. The built-in function almost does what we want, but doesn't loop. If we used the combination, we'd get an infinite loop, but we wouldn't be able to break out of it. So we need to roll our own loop:

The underscore after the name is a typical naming convention in Haskell for monadic functions that repeat but do not return a value. takes a predicate that signals when to stop, an action to perform before the test, and a function-returning-an-action to do to the input. Each of the latter two is generalized over any monad, not just. That's why we write their types using the type variable, and include the type constraint.

Note also that we can write recursive actions just as we write recursive functions.

Now that we have all the machinery in place, we can write our REPL easily:

And change our main function so it either executes a single expression, or enters the REPL and continues evaluating expressions until we type :

Compile and run the program, and try it out:

$ ghc -package parsec -fglasgow-exts -o lisp [../code/listing7.hs listing7.hs] $ ./lisp Lisp>>> (+ 2 3) 5 Lisp>>> (cons this ') Unrecognized special form: this Lisp>>> (cons 2 3) (2 . 3) Lisp>>> (cons 'this ') (this) Lisp>>> quit $


text:
Write Yourself a Scheme in 48 Hours/Adding Variables and Assignment

Finally, we get to the good stuff: variables. A variable lets us save the result of an expression and refer to it later. In Scheme, a variable can also be reset to new values, so that its value changes as the program executes. This presents a complication for Haskell, because the execution model is built upon functions that return values, but never change them.

Nevertheless, there are several ways to simulate state in Haskell, all involving monads. The simplest is probably the state monad, which lets you hide arbitrary state within the monad and pass it around behind the scenes. You specify the state type as a parameter to the monad (e.g. if a function returns an integer but modifies a list of string pairs, it would have type ), and access it via the get and put functions, usually within a do-block. You'd specify the initial state via the, which returns a pair containing the return value and the final state.

Unfortunately, the state monad doesn't work well for us, because the type of data we need to store is fairly complex. For a simple top-level environment, we could get away with, storing mappings from variable names to values. However, when we start dealing with function calls, these mappings become a stack of nested environments, arbitrarily deep. And when we add closures, environments might get saved in an arbitrary Function value, and passed around throughout the program. In fact, they might be saved in a variable and passed out of the  monad entirely, something we're not allowed to do.

Instead, we use a feature called state threads, letting Haskell manage the aggregate state for us. This lets us treat mutable variables as we would in any other programming language, using functions to get or set variables. There are two flavors of state threads: the monad creates a stateful computation that can be executed as a unit, without the state escaping to the rest of the program. The module lets you use stateful variables within the IO monad. Since our state has to be interleaved with IO anyway (it persists between lines in the REPL, and we will eventually have IO functions within the language itself), we'll be using s.

We can start out by importing and defining a type for our environments:

This declares an  as an   holding a list that maps  s to mutable  s. We need  s for both the list itself and for individual values because there are two ways that the program can mutate the environment. It might use  to change the value of an individual variable, a change visible to any function that shares that environment (Scheme allows nested scopes, so a variable in an outer scope is visible to all inner scopes). Or it might use  to add a new variable, which should be visible on all subsequent statements.

Since s can only be used within the IO monad, we'll want a helper action to create an empty environment. We can't just use the empty list  because all accesses to  s must be sequenced, and so the type of our null environment is   instead of just plain  :

From here, things get a bit more complicated, because we'll be simultaneously dealing with two monads. Remember, we also need an  monad to handle things like unbound variables. The parts that need IO functionality and the parts that may throw exceptions are interleaved, so we can't just catch all the exceptions and return only normal values to the IO monad.

Haskell provides a mechanism known as monad transformers that lets you combine the functionality of multiple monads. We'll be using one of these,, which lets us layer error-handling functionality on top of the IO monad. Our first step is to create a type synonym for our combined monad:

Like,   is really a type constructor: we've left off the last argument, the return type of the function. However,  takes one more argument than plain old  : we have to specify the type of monad that we're layering our error-handling functionality over. We've created a monad that may contain IO actions that throw a.

We have a mix of  and   functions, but actions of different types cannot be contained within the same do-block, even if they provide essentially the same functionality. Haskell already provides a mechanism, lifting, to bring values of the lower type into the combined monad. Unfortunately, there's no similar support to bring a value of the untransformed upper type into the combined monad, so we need to write it ourselves:

This destructures the  type and either re-throws the error type or returns the ordinary value. Methods in typeclasses resolve based on the type of the expression, so and  (members of  and, respectively) take on their   definitions. Incidentally, the type signature provided here is not fully general: if we'd left it off, the compiler would have inferred.

We'll also want a helper function to run the whole top-level  action, returning an IO action. We can't escape from the IO monad, because a function that performs IO has an effect on the outside world, and you don't want that in a lazily-evaluated pure function. But you can run the error computation and catch the errors.

This uses our previously-defined  function to take any error values and convert them to their string representations, then runs the whole computation via. The result is passed into  and returned as a value in the IO monad.

Now we're ready to return to environment handling. We'll start with a function to determine if a given variable is already bound in the environment, necessary for proper handling of :

This first extracts the actual environment value from its  via. Then we pass it to lookup to search for the particular variable we're interested in. lookup returns a  value, so we return   if that value was   and   otherwise (we need to use the  function because  expects a function to perform on the result and not just a value). Finally, we use return to lift that value into the IO monad. Since we're just interested in a true/false value, we don't need to deal with the actual  that lookup returns.

Next, we'll want to define a function to retrieve the current value of a variable:

Like the previous function, this begins by retrieving the actual environment from the. However,  uses the   monad, because it also needs to do some error handling. As a result, we need to use the function to lift the   action into the combined monad. Similarly, when we return the value, we use  to generate an   action that reads the returned. We don't need to use  to throw an error, however, because   is a defined for the typeclass, of which   is an instance.

Now we create a function to set values:

Again, we first read the environment out of its  and run a lookup on it. This time, however, we want to change the variable instead of just reading it. The action provides a means for this, but takes its arguments in the wrong order (ref -> value instead of value -> ref). So we use the built-in function to switch the arguments of   around, and then pass it the value. Finally, we return the value we just set, for convenience.

We'll want a function to handle the special behavior of, which sets a variable if already bound or creates a new one if not. Since we've already defined a function to set values, we can use it in the former case:

It's the latter case that's interesting, where the variable is unbound. We create an IO action (via do-notation) that creates a new  to hold the new variable, reads the current value of the environment, then writes a new list back to that variable consisting of the new (key, variable) pair added to the front of the list. Then we lift that whole do-block into the  monad with.

There's one more useful environment function: being able to bind a whole bunch of variables at once, as happens when a function is invoked. We might as well build that functionality now, though we won't be using it until the next section:

This is perhaps more complicated than the other functions, since it uses a monadic pipeline (rather than do-notation) and a pair of helper functions to do the work. It's best to start with the helper functions. addBinding takes a variable name and value, creates an  to hold the new variable, and then returns the name–value pair. calls  on each member of bindings  to create a list of   pairs, and then appends the current environment to the end of that. Finally, the whole function wires these functions up in a pipeline, starting by reading the existing environment out of its, then passing the result to  , then returning a new   with the extended environment.

Now that we have all our environment functions, we need to start using them in the evaluator. Since Haskell has no global variables, we'll have to thread the environment through the evaluator as a parameter. While we're at it, we might as well add the and  special forms.

Since a single environment gets threaded through a whole interactive session, we need to change a few of our IO functions to take an environment.

We need the  in evalString because the type of the monad has changed from   to. Similarly, we need a  to bring   into the   monad.

Next, we initialize the environment with a null variable before starting the program:

We've created an additional helper function runOne to handle the single-expression case, since it's now somewhat more involved than just running. The changes to  are a bit more subtle: notice how we added a function composition operator before evalAndPrint. That's because  now takes an additional   parameter, fed from. The function composition tells  that instead of taking plain old   as an action, it ought to apply it first to whatever's coming down the monadic pipeline, in this case the result of. Thus, the actual function that gets applied to each line of input is, just as we want it.

Finally, we need to change our main function to call  instead of evaluating   directly:

And we can compile and test our program:

$ ghc -package parsec -o lisp [../code/listing8.hs listing8.hs] $ ./lisp Lisp>>> (define x 3) 3 Lisp>>> (+ x 2) 5 Lisp>>> (+ y 2) Getting an unbound variable: y Lisp>>> (define y 5) 5 Lisp>>> (+ x (- y 2)) 6 Lisp>>> (define str "A string") "A string" Lisp>>> (< str "The string") Invalid type: expected number, found "A string" Lisp>>> (string<? str "The string") #t


text:
Write Yourself a Scheme in 48 Hours/Defining Scheme Functions

Now that we can define variables, we might as well extend it to functions. After this section, you'll be able to define your own functions within Scheme and use them from other functions. Our implementation is nearly finished.

Let's start by defining new  constructors:

We've added a separate constructor for primitives, because we'd like to be able to store,  , etc. in variables and pass them to functions. The  constructor stores a function that takes a list of arguments to a , the same type that is stored in our primitive list.

We also want a constructor to store user-defined functions. We store four pieces of information:

 * 1) the names of the parameters, as they're bound in the function body;
 * 2) whether the function accepts a variable-length list of arguments, and if so, the variable name it's bound to;
 * 3) the function body, as a list of expressions;
 * 4) the environment that the function was created in.

This is an example of a record type. Records are somewhat clumsy in Haskell, so we're only using them for demonstration purposes. However, they can be invaluable in large-scale programming.

Next, we'll want to edit our  function to include the new types:

Instead of showing the full function, we just print out the word  for primitives and the header info for user-defined functions. This is an example of pattern-matching for records: as with normal algebraic types, a pattern looks exactly like a constructor call. Field names come first and the variables they'll be bound to come afterwards.

Next, we need to change. Instead of being passed the name of a function, it'll be passed a  representing the actual function. For primitives, that makes the code simpler: we need only read the function out of the value and apply it.

The interesting code happens when we're faced with a user defined function. Records let you pattern match on both the field name (as shown above) or the field position, so we'll use the latter form:

The very first thing this function does is check the length of the parameter list against the expected number of arguments. It throws an error if they don't match. We define a local function  to enhance readability and make the program a bit shorter.

Assuming the call is valid, we do the bulk of the call in monadic pipeline that binds the arguments to a new environment and executes the statements in the body. The first thing we do is zip the list of parameter names and the list of (already evaluated) argument values together into a list of pairs. Then, we take that and the function's closure (not the current environment – this is what gives us lexical scoping) and use them to create a new environment to evaluate the function in. The result is of type, while the function as a whole is  , so we need to   it into the combined monad.

Now it's time to bind the remaining arguments to the varargs variable, using the local function. If the function doesn't take  (the   clause), then we just return the existing environment. Otherwise, we create a singleton list that has the variable name as the key and the remaining args as the value, and pass that to bindVars. We define the local variable  for readability, using the built-in function  to ignore all the arguments that have already been bound to variables.

The final stage is to evaluate the body in this new environment. We use the local function  for this, which maps the monadic function   over every statement in the body, and then returns the value of the last statement.

Since we're now storing primitives as regular values in variables, we have to bind them when the program starts up:

This takes the initial null environment, makes a bunch of name/value pairs consisting of PrimitiveFunc wrappers, and then binds the new pairs into the new environment. We also want to change  and   to   instead:

Finally, we need to change the evaluator to support and function. We'll start by creating a few helper functions to make it a little easier to create function objects in the  monad:

Here,  and   should just be considered specializations of   with the first argument set appropriately for normal functions vs. variable args. This is a good example of how to use first-class functions to simplify code.

Now, we can use them to add our extra eval clauses. They should be inserted after the define-variable clause and before the function-application one:

The following needs to replace the prior function-application eval clause.

As you can see, they just use pattern matching to destructure the form and then call the appropriate function helper. In define's case, we also feed the output into  to bind a variable in the local environment. We also need to change the function application clause to remove the  function, since apply now works in the   monad.

We can now compile and run our program, and use it to write real programs!

$ ghc -package parsec -fglasgow-exts -o lisp [../code/listing9.hs listing9.hs] $ ./lisp Lisp>>> (define (f x y) (+ x y)) (lambda ("x" "y") ...) Lisp>>> (f 1 2) 3 Lisp>>> (f 1 2 3) Expected 2 args; found values 1 2 3 Lisp>>> (f 1) Expected 2 args; found values 1 Lisp>>> (define (factorial x) (if (= x 1) 1 (* x (factorial (- x 1))))) (lambda ("x") ...) Lisp>>> (factorial 10) 3628800 Lisp>>> (define (counter inc) (lambda (x) (set! inc (+ x inc)) inc)) (lambda ("inc") ...) Lisp>>> (define my-count (counter 5)) (lambda ("x") ...) Lisp>>> (my-count 3) 8 Lisp>>> (my-count 6) 14 Lisp>>> (my-count 5) 19


text:
Write Yourself a Scheme in 48 Hours/Creating IO Primitives

Our Scheme can't really communicate with the outside world yet, so it would be nice if we could give it some I/O functions. Also, it gets really tedious typing in functions every time we start the interpreter, so it would be nice to load files of code and execute them.

The first thing we'll need is a new constructor for s.  s have a specific type signature that doesn't include the IO monad, so they can't perform any IO. We want a dedicated constructor for primitive functions that perform IO:

While we're at it, let's also define a constructor for the Scheme data type of a port. Most of our IO functions will take one of these to read from or write to:

A is basically the Haskell notion of a port: it's an opaque data type, returned from   and similar IO actions, that you can read and write to.

For completeness, we ought to provide  methods for the new data types:

This'll let the REPL function properly and not crash when you use a function that returns a port.

We also need to update apply, so that it can handle :

We'll need to make some minor changes to our parser to support. Since Scheme files usually contain several definitions, we need to add a parser that will support several expressions, separated by whitespace. And it also needs to handle errors. We can reuse much of the existing infrastructure by factoring our basic readExpr so that it takes the actual parser as a parameter:

Again, think of both  and   as specializations of the newly-renamed. We'll be using  in our REPL to read single expressions; we'll be using   from within load to read programs.

Next, we'll want a new list of IO primitives, structured just like the existing primitive list:

The only difference here is in the type signature. Unfortunately, we can't use the existing primitive list because lists cannot contain elements of different types. We also need to change the definition of  to add our new primitives:

We've generalized makeFunc to take a constructor argument, and now call it on the list of  in addition to the plain old primitives.

Now we start defining the actual functions. is a very thin wrapper around apply, responsible for destructuring the argument list into the form apply expects:

wraps the Haskell function, converting it to the right type and wrapping its return value in the   constructor. It's intended to be partially-applied to the,   for   and   for  :

also wraps the equivalent Haskell procedure, this time :

(named to avoid a name conflict with the built-in read) wraps the Haskell  and then sends the result to , to be turned into a   suitable for Scheme:

Notice how  is of type   yet   is of type , so they both need to be converted (with   and  , respectively) to the   monad. Only then can they be piped together with the monadic bind operator.

converts a  to a string and then writes it out on the specified port:

We don't have to explicitly call show on the object we're printing, because  takes a value of type. It's calling show for us automatically. This is why we bothered making  an instance of  ; otherwise, we wouldn't be able to use this automatic conversion and would have to call   ourselves. Many other Haskell functions also take instances of, so if we'd extended this with other IO primitives, it could save us significant labor.

reads the whole file into a string in memory. It's a thin wrapper around Haskell's, again just lifting the IO action into an   action and wrapping it in a   constructor:

The helper function  doesn't do what Scheme's load does (we handle that later). Rather, it's responsible only for reading and parsing a file full of statements. It's used in two places:  (which returns a list of values) and   (which evaluates those values as Scheme expressions).

then just wraps that return value with the  constructor:

Implementing the actual Scheme  function is a little tricky, because   can introduce bindings into the local environment. Apply, however, doesn't take an environment argument, and so there's no way for a primitive function (or any function) to do this. We get around this by implementing  as a special form:

Finally, we might as well change our  function so that instead of evaluating a single expression from the command line, it takes the name of a file to execute and runs that as a program. Additional command-line arguments will get bound into a list  within the Scheme program:

That's a little involved, so let's go through it step-by-step. The first line takes the original primitive bindings, passes that into, and then adds a variable named   that's bound to a   containing   versions of all but the first argument. (The first argument is the filename to execute.) Then, it creates a Scheme form, just as if the user had typed it in, and evaluates it. The result is transformed to a string (remember, we have to do this before catching errors, because the error handler converts them to strings and the types must match) and then we run the whole  action. Then we print the result on. (Traditional UNIX conventions hold that  should be used only for program output, with any error messages going to  . In this case, we'll also be printing the return value of the last statement in the program, which generally has no meaning to anything.)

Then we change main so it uses our new  function. Since we no longer need a third clause to handle the wrong number of command-line arguments, we can simplify it to an if statement:


text:
Write Yourself a Scheme in 48 Hours/Towards a Standard Library

Our Scheme is almost complete now, but it's still rather hard to use. At the very least, we'd like a library of standard list manipulation functions that we can use to perform some common computations.

Rather than using a typical Scheme implementation, defining each list function in terms of a recursion on lists, we'll implement two primitive recursion operators ( and  ) and then define our whole library based on those. This style is used by the Haskell Prelude: it gives you more concise definitions, less room for error, and good practice using fold to capture iteration.

We'll start by defining a few obvious helper functions. and  are defined exactly as you'd expect it, using if statements:

We can use the varargs feature to define list, which just returns a list of its arguments:

We also want an  function, which just returns its argument unchanged. This may seem completely useless – if you already have a value, why do you need a function to return it? However, several of our algorithms expect a function that tells us what to do with a given value. By defining, we let those higher-order functions work even if we don't want to do anything with the value.

Similarly, it'd be nice to have a  function, in case we want to pass in a function that takes its arguments in the wrong order:

Finally, we add  and , which work like their Haskell equivalents (partial application and the dot operator, respectively).

We might as well define some simple library functions that appear in the Scheme standard:

These are basically done just as you'd expect them. Note the usage of curry to define,   and. We bind the variable  to the function returned by curry, giving us a unary function that returns true if its argument is equal to zero.

Next, we want to define a fold function that captures the basic pattern of recursion over a list. The best way to think about fold is to picture a list in terms of its infix constructors:  in Haskell or   in Scheme. A fold function replaces every constructor with a binary operation, and replaces  with the accumulator. So, for example,.

With that definition, we can write our fold function. Start with a right-associative version to mimic the above examples:

The structure of this function mimics our definition almost exactly. If the list is null, replace it with the end value. If not, apply the function to the car of the list and to the result of folding this function and end value down the rest of the list. Since the right-hand operand is folded up first, you end up with a right-associative fold.

We also want a left-associative version. For most associative operations like  and   the two of them are completely equivalent. However, there is at least one important binary operation that is not associative: cons. For all our list manipulation functions, then, we'll need to deliberately choose between left- and right-associative folds.

This begins the same way as the right-associative version, with the test for null that returns the accumulator. This time, however, we apply the function to the accumulator and first element of the list, instead of applying it to the first element and the result of folding the list. This means that we process the beginning first, giving us left-associativity. Once we reach the end of the list,, we then return the result that we've been progressively building up.

Note that func takes its arguments in the opposite order from. In, the accumulator represents the rightmost value to tack onto the end of the list, after you've finished recursing down it. In, it represents the completed calculation for the leftmost part of the list. In order to preserve our intuitions about commutativity of operators, it should therefore be the left argument of our operation in, but the right argument in.

Once we've got our basic folds, we can define a couple of convenience names to match typical Scheme usage:

These are just new variables bound to the existing functions: they don't define new functions. Most Schemes call  " " or plain old " ", and don't make the distinction between   and. We define it to be, which happens to be tail-recursive and hence runs more efficiently than   (it doesn't have to recurse all the way down to the end of the list before it starts building up the computation). Not all operations are associative, however; we'll see some cases later where we have to use  to get the right result.

Next, we want to define a function that is the opposite of. Given a unary function, an initial value, and a unary predicate, it continues applying the function to the last value until the predicate is true, building up a list as it goes along.

As usual, our function structure basically matches the definition. If the predicate is true, then we cons a  onto the last value, terminating the list. Otherwise, cons the result of unfolding the next value  onto the current value.

In academic functional programming literature, folds are often called catamorphisms, unfolds are often called anamorphisms, and the combinations of the two are often called hylomorphisms. They're interesting because any for-each loop can be represented as a catamorphism. To convert from a loop to a foldl, package up all mutable variables in the loop into a data structure (records work well for this, but you can also use an algebraic data type or a list). The initial state becomes the accumulator; the loop body becomes a function with the loop variables as its first argument and the iteration variable as its second; and the list becomes, well, the list. The result of the fold function is the new state of all the mutable variables.

Similarly, every for-loop (without early exits) can be represented as a hylomorphism. The initialization, termination, and step conditions of a for-loop define an anamorphism that builds up a list of values for the iteration variable to take. Then, you can treat that as a for-each loop and use a catamorphism to break it down into whatever state you wish to modify.

Let's go through a couple examples. We'll start with typical,  ,   &   functions:

These all follow from the definitions:

Since all of these operators are associative, it doesn't matter whether we use  or. We replace the cons constructor with the operator, and the nil constructor with the identity element for that operator.

Next, let's try some more complicated operators. and  find the maximum and minimum of their arguments, respectively:

It's not immediately obvious what operation to fold over the list, because none of the built-ins quite qualify. Instead, think back to fold as a representation of a foreach loop. The accumulator represents any state we've maintained over previous iterations of the loop, so we'll want it to be the maximum value we've found so far. That gives us our initialization value: we want to start off with the leftmost variable in the list (since we're doing a ). Now recall that the result of the operation becomes the new accumulator at each step, and we've got our function. If the previous value is greater, keep it. If the new value is greater, or they're equal, return the new value. Reverse the operation for.

How about ? We know that we can find the length of a list by counting down it, but how do we translate that into a fold?

Again, think in terms of its definition as a loop. The accumulator starts off at 0 and gets incremented by 1 with each iteration. That gives us both our initialization value, 0, and our function,. Another way to look at this is "The length of a list is 1 + the length of the sublist to its left".

Let's try something a bit trickier:.

The function here is fairly obvious: if you want to reverse two  cells, you can just   so it takes its arguments in the opposite order. However, there's a bit of subtlety at work. Ordinary lists are right associative:. If you want to reverse this, you need your fold to be left associative:. Try it with a  instead of a foldl and see what you get.

There's a whole family of  and   functions, all of which can be represented with folds. The particular lambda expression is fairly complicated though, so let's factor it out:

The helper function is parameterized by the predicate to use and the operation to apply to the result if found. Its accumulator represents the first value found so far: it starts out with  and takes on the first value that satisfies its predicate. We avoid finding subsequent values by testing for a non- value and returning the existing accumulator if it's already set. We also provide an operation that will be applied to the next value each time the predicate tests: this lets us customize  to check the value itself (for  ) or only the key of the value (for  ).

The rest of the functions are just various combinations of,  ,   and  ,  , folded over the list with an initial value of.

Next, let's define the functions  and. applies a function to every element of a list, returning a new list with the transformed values:

Remember that 's function takes its arguments in the opposite order as , with the current value on the left. Map's lambda applies the function to the current value, then conses it with the rest of the mapped list, represented by the right-hand argument. It's essentially replacing every infix cons constructor with one that conses, but also applies the function to its left-side argument.

keeps only the elements of a list that satisfy a predicate, dropping all others:

This works by testing the current value against the predicate. If it's true, replacing cons with, i.e., don't do anything. If it's false, drop the  and just return the rest of the list. This eliminates all the elements that don't satisfy the predicate, consing up a new list that includes only the ones that do.

We can use the standard library by starting up our Lisp interpreter and typing :

$ ./lisp Lisp>>> (load "stdlib.scm") (lambda ("pred". lst) ...) Lisp>>> (map (curry + 2) '(1 2 3 4)) (3 4 5 6) Lisp>>> (filter even? '(1 2 3 4)) (2 4) Lisp>>> quit

There are many other useful functions that could go into the standard library, including,  , append, and various string-manipulation functions. Try implementing them as folds. Remember, the key to successful fold programming is thinking only in terms of what happens on each iteration. Fold captures the pattern of recursion down a list, and recursive problems are best solved by working one step at a time.


text:
Template:Auto navigation

Next Page:  ../ /  Home:  ../ Example

title: Template:Auto navigation


text:
Write Yourself a Scheme in 48 Hours/Conclusion

You now have a working Scheme interpreter that implements a large chunk of the standard, including functions, lambdas, lexical scoping, symbols, strings, integers, list manipulation, and assignment. You can use it interactively, with a REPL, or in batch mode, running script files. You can write libraries of Scheme functions and either include them in programs or load them into the interactive interpreter. With a little text processing via awk or sed, you can format the output of UNIX commands as parenthesized Lisp lists, read them into a Scheme program, and use this interpreter for shell scripting.

There are still a number of features you could add to this interpreter. Hygienic macros let you perform transformations on the source code before it's executed. They're a very convenient feature for adding new language features, and several standard parts of Scheme (such as let-bindings and additional control flow features) are defined in terms of them. Section 4.3 of R5RS defines the macro system's syntax and semantics, and there is a whole collection of papers on implementation. Basically, you'd want to intersperse a function between readExpr and eval that takes a form and a macro environment, looks for transformer keywords, and then transforms them according to the rules of the pattern language, rewriting variables as necessarily.

Continuations are a way of capturing "the rest of the computation", saving it, and perhaps executing it more than once. Using them, you can implement just about every control flow feature in every major programming language. The easiest way to implement continuations is to transform the program into continuation-passing style, so that eval takes an additional continuation argument and calls it, instead of returning a result. This parameter gets threaded through all recursive calls to eval, but is only manipulated when evaluating a call to call-with-current-continuation.

Dynamic-wind could be implemented by keeping a stack of functions to execute when leaving the current continuation and storing (inside the continuation data type) a stack of functions to execute when resuming the continuation.

If you're just interested in learning more Haskell, there are a large number of libraries that may help:

 * For webapps: WASH, a monadic web framework
 * For databases: haskelldb, a library that wraps SQL as a set of Haskell functions, giving you all the type-safety of the language when querying the database
 * For GUI programming: Fudgets and wxHaskell. wxHaskell is more of a conventional MVC GUI library, while Fudgets includes a lot of new research about how to represent GUIs in functional programming languages
 * For concurrency: Software Transactional Memory, described in the paper Composable Memory Transactions
 * For networking: GHC's Networking libraries

This should give you a starting point for further investigations into the language. Happy hacking!

Acknowledgements
Thanks to Ketil Malde, Pete Kazmier, and Brock for sending in questions and suggestions about this tutorial. Additional comments, clarifications, and corrections should go on the discussion page of this tutorial.


text:
Talk:Write Yourself a Scheme in 48 Hours

Mistake in PDF version
On page 19, the parseExpr function which should return either a parseAtom, a parseString or a parseNumber successful parse result excludes the parseNumber part (<|> parseNumber). 89.56.172.134 (talk) 20:52, 31 July 2009 (UTC)

To do

 * Import or link to code listings
 * Update all examples that link to code listings
 * Code listings are no longer on specified site. Please update and post new site.
 * The code could be inserted by hand, but where the code should be uploaded to be accessed by others to fix the errors.

Question
Can we create a place for the answers to the exercises?

 * Sounds like a nice idea -- Kowey 04:44, 21 August 2006 (UTC)

 * I'm working on it! Please help!! --Jkarres 03:52, 29 March 2007 (UTC)

 * One thought: it might be useful if we put exercises in subpages for each module. But then again, this book is pretty stable, so it doesn't matter much either way.  -- Kowey 06:36, 29 March 2007 (UTC)

Thanks for this tutorial. You nearly lost me in chapter 7 (Adding Variables and Assignment: Mutable State in Haskell), but I made it. I had some experience in both Scheme and Haskell (and lots of experience in C).

Environment bug
There is a rather nasty bug in the implementation of environments for the scheme implemented by this tutorial where instead of lexical scoping, dynamic scoping was implemented. Interestingly enough, this same bug occurred in the original implementation of Lisp. Basically,

Then, do. The result is, as expected, 5. However, unexpectedly  is now 5, too, despite R5RS scoping rules. I'm not sure how much needs to be edited to fix this. 18.224.0.122 (talk) 23:32, 5 June 2009 (UTC)

 * And, actually, I have a reference implementation for environments in (which also has cons cells so that   and   could potentially work).  The main functions are those which have "env" in them. 18.224.0.122 (talk) 23:39, 5 June 2009 (UTC)

Derivative Implementations

 * husk scheme - I extended the code examples from this book and wrote a more fully-featured Scheme that includes continuations, macros, etc. This is a good reference point for anyone interested in the nuts and bolts of how more advanced features could be implemented.

 * haskeem - This is another Scheme implementation derived from examples in this book, and includes a good amount of R5RS functionality.

Disclaimer - As Uwe wrote, you will learn more by writing all of this yourself. If you really want to learn Scheme, I recommend you work through the whole book on your own, and then try to implement some of these more advanced features yourself. And perhaps contribute a patch or two to one of these projects :)

Compiler Warning for the 'cdr' function
compiling listing10.hs gives the warning:

Lisp.hs:225:1: Warning: Pattern match(es) are overlapped In an equation for `cdr': cdr [DottedList [xs] x] = ...

I am pretty sure that this not a problem and can be ignored.

 * Swapping that one with  above it removes the warning.   returns 2 as expected. 75.33.209.194 (discuss) 08:40, 26 November 2013 (UTC)

many quotes are omited
The book has examples committing quotes. One example is:  which is wrong, it should be either   or. Quote is need if  is a symbol, otherwise   would be interpreted as a function name. I suppose they were deleted from the original code by mistake. 2806:106E:B:B370:7DC0:FB79:8026:6B8A (discuss) 08:02, 11 November 2022 (UTC)


text:
Java Programming/API/java.lang.String

is a class built into the Java language defined in the  package. It represents character strings. Strings are ubiquitous in Java. Study the  class and its methods carefully. It will serve you well to know how to manipulate them skillfully. String literals in Java programs, such as "abc", are implemented as instances of this class like this:

On the right hand side a String object is created represented by the string literal. Its object reference is assigned to the  variable.

Immutability
Strings are immutable; that is, they cannot be modified once created. Whenever it looks as if a String object was modified actually a new String object was created. For instance, the  method returns the string with leading and trailing whitespace removed. Actually, it creates a new trimmed string and then returns it. Pay attention on what happens in Code section 3.82:

The  method call does not modify the object so nothing happens. It creates a new trimmed string and then throws it away.

The returned string is assigned to the variable. It does the job as the  method has created a new   instance.

Concatenation
The Java language provides special support for the string concatenation with operator :

The concatenation is not always processed at the same time. Raw string literals concatenation is done at compile time, hence there is a single string literal in the byte code of the class. Concatenation with at least one object is done at runtime.

operator can concatenate other objects with strings. For instance, integers will be converted to strings before the concatenation:

Each Java object has the  inherited from the  class. This method provides a way to convert objects into s. Most classes override the default behavior to provide more specific (and more useful) data in the returned  :

Using StringBuilder/StringBuffer to concatenate strings
Remember that  objects are immutable objects. Once a  is created, it can not be modified, takes up memory until garbage collected. Be careful of writing a method like this:

On the  operation a new  object is created at each iteration. Suppose  contains the elements. At runtime, the method creates thirteen s: Even though only the last one is actually useful.

To avoid unnecessary memory use like this, use the  class. It provides similar functionality to s, but stores its data in a mutable way. Only one  object is created. Also because object creation is time consuming, using  produces much faster code.

As  isn't thread safe (see the chapter on Concurrency) you can't use it in more than one thread. For a multi-thread environment, use  instead which does the same and is thread safe. However,  is slower so only use it when it is required. Moreover, before Java 5 only  existed.

Comparing Strings
Comparing strings is not as easy as it may first seem. Be aware of what you are doing when comparing 's using  :

The difference between the above and below code is that the above code checks to see if the 's are the same objects in memory which they are. This is as a result of the fact that 's are stored in a place in memory called the String Constant Pool. If the  keyword is not explicitly used when creating the  it checks to see if it already exists in the Pool and uses the existing one. If it does not exist, a new Object is created. This is what allows Strings to be immutable in Java. To test for equality, use the  method inherited by every class and defined by   to return  if and only if the object passed in is a   contains the exact same data:

Remember that the comparison is case sensitive.

To order  objects, use the   method, which can be accessed wherever we use a String datatype. The  method returns a negative, zero, or positive number if the parameter is less than, equal to, or greater than the object on which it is called. Let's take a look at an example:

The code section 3.92 is comparing the String variable  to. If  is different even in the slightest manner, we will get a value above or below 0 depending on the exact difference. The result is negative if this String object lexicographically precedes the argument string. The result is positive if this String object lexicographically follows the argument string. Take a look at the Java API for more details.

Splitting a String
Sometimes it is useful to split a string into separate strings, based on a regular expressions. The class has a   method, since Java 1.4, that will return a String array:

Another useful application could be to split the String text based on the new line character, so you could process the text line by line.

Substrings
It may also be sometimes useful to create substrings, or strings using the order of letters from an existing string. This can be done in two methods.

The first method involves creating a substring out of the characters of a string from a given index to the end:

The index of the first character in a string is 0.

By counting from there, it is apparent that the character in index 3 is the second "f" in "coffee". This is known as the. All characters from the  until the end of the string will be copied into the new substring.

The second method involves a user-defined  and  :

The string returned by  would be "port".

Please note that the endIndex is not inclusive. This means that the last character will be of the index. Therefore, in this example, every character from index 3 to index 6, inclusive, was copied into the substring.

String cases
The  class also allows for the modification of cases. The two methods that make this possible are  and.

These methods are useful to do a search which is not case sensitive:

Question 3.12: You have mail addresses in the following form:

Write the  method that receives the mail string as parameter and returns the readable person name like this:

 * 1) We only process non null strings,
 * 2) We first split the mail into two parts to separate the personal information from the company information and we keep the name data,
 * 3) Then we split the name information to separate the first name from the last name. As the   method use regular expression and   is a wildcard character, we have to escape it . However, in a string, the   is also a special character, so we need to escape it too ,
 * 4) The last name is just capitalized,
 * 5) As the case of all the first name characters will not be the same, we have to cut the first name. Only the first name initial will be capitalized,
 * 6) Now we can concatenate all the fragments. We prefer to use a   to do that.

title: Java Programming/API/java.lang.String


text:
Talk:Bartending/Contributors

Jfdunphy 04:17, 9 July 2006 (UTC)For the record, I took my bartending licence with the New Jersey (USA) Bartender's School in Montclair, NJ, so I added to the reference section the text we used, the Bartender's Black book, which has the advantage of laying flat on the bar while you mix a drink, so you don't have to fumble with the book while trying to mix a drink. In addition, I've added references to a couple of books and pamphlets that seemed useful. More later.

title: Talk:Bartending/Contributors


text:
User talk:BradPatrick

This is a talk page, however, I respond more readily to email. Please use the "email this user" button to the left. Thanks.--BradPatrick 11:52, 9 July 2006 (UTC)

title: User talk:BradPatrick


text:
Haskell/Next steps

This chapter introduces pattern matching and two new pieces of syntax:  expressions and   bindings.

if / then / else
Haskell syntax supports garden-variety conditional expressions of the form if... then... else.... For instance, consider a function that returns  if its argument is less than  ;   if its argument is  ; and   if its argument is greater than. The predefined  function does that job already; but for the sake of illustration, let's define a version of our own:

The parentheses around "-1" in the last example are required; if missing, Haskell will think that you are trying to subtract  from   (which would give a type error).

In an if/then/else construct, first the condition (in this case ) is evaluated. If it results, the whole construct evaluates to the then expression; otherwise (if the condition is  ), the construct evaluates to the else expression. All of that is pretty intuitive. If you have programmed in an imperative language before, however, it might seem surprising to know that Haskell always requires both a then and an else clause. The construct has to result in a value in both cases and, specifically, a value of the same type in both cases.

Function definitions using if / then / else like the one above can be rewritten using Guards.

Similarly, the absolute value function defined in Truth values can be rendered with an if/then/else:

Why use if/then/else versus guards? As you will see with later examples and in your own programming, either way of handling conditionals may be more readable or convenient depending on the circumstances. In many cases, both options work equally well.

Introducing pattern matching
Consider a program which tracks statistics from a racing competition in which racers receive points based on their classification in each race, the scoring rules being: We can write a simple function which takes a classification (represented by an integer number:  for first place, etc. ) and returns how many points were earned. One possible solution uses if/then/else:
 * 10 points for the winner;
 * 6 for second-placed;
 * 4 for third-placed;
 * 3 for fourth-placed;
 * 2 for fifth-placed;
 * 1 for sixth-placed;
 * no points for other racers.

Yuck! Admittedly, it wouldn't look this hideous had we used guards instead of if/then/else, but it still would be tedious to write (and read!) all those equality tests. We can do better, though:

Much better. However, even though defining  in this style (which we will arbitrarily call piece-wise definition from now on) shows to a reader of the code what the function does in a clear way, the syntax looks odd given what we have seen of Haskell so far. Why are there seven equations for ? What are those numbers doing in their left-hand sides? What about variable arguments?

This feature of Haskell is called pattern matching. When we call, the argument is matched against the numbers on the left side of each of the equations, which in turn are the patterns. The matching is done in the order we wrote the equations. First, the argument is matched against the  in the first equation. If the argument is indeed, we have a match and the first equation is used; so   evaluates to   as expected. Otherwise, the other equations are tried in order following the same procedure. The final one, though, is rather different: the  is a special pattern, often called a "wildcard", that might be read as "whatever": it matches with anything; and therefore if the argument doesn't match any of the previous patterns   will return zero.

As for the lack of  or any other variable standing for the argument, we simply don't need that to write the definitions. All possible return values are constants. Besides, variables are used to express relationships on the right side of the definition, so the  is unnecessary in our   function.

However, we could use a variable to make  even more concise. The points given to a racer decrease regularly from third place to sixth place, at a rate of one point per position. After noticing that, we can eliminate three of the seven equations as follows:

So, we can mix both styles of definitions. In fact, when we write  in the left side of an equation we are using pattern matching too! As a pattern, the  (or any other variable name) matches anything just like  ; the only difference being that it also gives us a name to use on the right side (which, in this case, is necessary to write  ).

Beyond integers, pattern matching works with values of various other types. One handy example is booleans. For instance, the  logical-or operator we met in Truth values could be defined as:

Or:

When matching two or more arguments at once, the equation will only be used if all of them match.

Now, let's discuss a few things that might go wrong when using pattern matching:

 * If we put a pattern which matches anything (such as the final patterns in each of the  example) before the more specific ones the latter will be ignored. GHC(i) will typically warn us that "Pattern match(es) are overlapped" in such cases.
 * If no patterns match, an error will be triggered. Generally, it is a good idea to ensure the patterns cover all cases, in the same way that the  guard is not mandatory but highly recommended.
 * Finally, while you can play around with various ways of (re)defining here is one version that will not work:

 * The program won't test whether the arguments are equal just because we happened to use the same name for both. As far as the matching goes, we could just as well have written  in the first case. And even worse: because we gave the same name to both arguments, GHC(i) will refuse the function due to "Conflicting definitions for `x'".

Tuple and list patterns
While the examples above show that pattern matching helps in writing more elegant code, that does not explain why it is so important. So, let's consider the problem of writing a definition for, the function which extracts the first element of a pair. At this point, that appears to be an impossible task, as the only way of accessing the first value of the pair is by using  itself... The following function, however, does the same thing as  (confirm it in GHCi):

It's magic! Instead of using a regular variable in the left side of the equation, we specified the argument with the pattern of the 2-tuple - that is,  - filled with a variable and the   pattern. Then the variable was automatically associated with the first component of the tuple, and we used it to write the right side of the equation. The definition of  is, of course, analogous.

Furthermore, the trick demonstrated above can be done with lists as well. Here are the actual definitions of  and  :

The only essential change in relation to the previous example was replacing  with the pattern of the cons operator. These functions also have an equation using the pattern of the empty list, ; however, since empty lists have no head or tail there is nothing to do other than use   to print a prettier error message.

In summary, the power of pattern matching comes from its use in accessing the parts of a complex value. Pattern matching on lists, in particular, will be extensively deployed in Recursion and the chapters that follow it. Later on, we will explore what is happening behind this seemingly magical feature.

let bindings
To conclude this chapter, a brief word about  bindings (an alternative to   clauses for making local declarations). For instance, take the problem of finding the roots of a polynomial of the form $$ax^2+bx+c$$ (in other words, the solution to a second degree equation — think back to your middle school math courses). Its solutions are given by:
 * $$x = \frac {-b \pm \sqrt{b^2-4ac}} {2a}$$.

We could write the following function to compute the two values of $$x$$:

Writing the  term in both cases is annoying, though; we can use a local binding instead, using either   or, as will be demonstrated below, a   declaration:

We put the  keyword before the declaration, and then use   to signal we are returning to the "main" body of the function. It is possible to put multiple declarations inside a single ... block — just make sure they are indented the same amount or there will be syntax errors:

title: Haskell/Next steps


text:
Asymptote

This is a user-maintained reference to the Asymptote markup language. It is intended that this can serve as a useful resource for everyone from new users who wish to learn, to old hands who need a quick reference.

Howto
This section should contain recipes for different tasks.

Command reference
Please help to make the command pages:

asy -l | grep '('

and add the functions to the command page along with info and examples.

plain
This is the default Asymptote base file, which defines key parts of the drawing language (such as the picture structure). By default, an implicit private import plain; occurs before translating a file and before the first command given in interactive mode. This also applies when translating files for module definitions (except when translating plain, of course). This means that the types and functions defined in plain are accessible in almost all Asymptote code. Use the -noautoplain command-line option to disable this feature.

abort abs acos acosh add alias align all angle arc ArcArrow ArcArrows arcarrowsize arcdir arclength arcpoint arctime arrow Arrow arrow2 arrowhead arrowheadbbox Arrows arrowsize asin asinh ask atan atan2 atanh atexit attach AvantGarde axialshade azimuth bar Bar Bars barsize basealign baseline bbox BeginArcArrow BeginArrow BeginBar beginclip BeginDotMargin begingroup BeginMargin BeginPenMargin beginpoint Blank Bookman box cap cast cbrt cd ceil Ceil circle clear clip close cmyk colatitude colors complement concat conj controls copy cos cosh Courier cross csv cubiclength cubicroots curl cycle cyclic deconstruct defaultpen degrees Degrees dimension dir dirtime dot DotMargin DotMargins dotsize Dotted _draw draw Draw ecast ellipse empty EndArcArrow EndArrow EndBar endclip EndDotMargin endgroup endl EndMargin EndPenMargin endpoint eof eol erase erf erfc error _eval eval execute exitfunction exp expi fabs fft fill Fill filldraw fillrule filltype find finite firstcut floor Floor flush fmod font fontcommand fontsize format gamma getc getint getpair getreal getstring gouraudshade graphic gray grestore gsave gui GUI GUIop GUIreset Helvetica hypot identity image init initdefaults input insert inside interact interp intersect intersectionpoint inverse invisible italic J label Label labelmargin labels Landscape lastcut latitude latticeshade layer legend length line linecap linejoin lineskip linetype linewidth log log10 longitude Longitude makedraw makepen map margin Margin Margins marginT Mark marker marknodes markroutine markuniform math max maxbound maxcoords merge MidArcArrow MidArrow midpoint min minbound minipage NewCenturySchoolBook newpage nib NoFill NoMargin none None nullexitfcn orientation output overwrite Palatino pattern pause Pen PenMargin PenMargins point polar polygon Portrait postcontrol postscript pow10 precision precontrol prepend quadraticroots quiet quotient radialshade RadialShade rand read1 read2 read3 readGUI readline realmult rectify reflect relative Relative - specifies a relative location. relativedistance reldir relpoint reltime remainder replace resetdefaultpen restore restoredefaults reverse rfind rgb rotate round Round scale scroll search Seascape seek sequence sgn shift shiftless shipout sin single sinh size slant solve sort spec sqrt srand straight subpath substr suffix sum Symbol system tab tan tanh tell tension tex texify TeXify texpreamble time TimesRoman transpose tridiagonal trim TrueMargin unfill UnFill unit uptodate VERSION write xinput xoutput xpart xscale xtrans Y ypart yscale ytrans ZapfChancery ZapfDingbats zpart

simplex
This package solves the two-variable linear programming problem using the simplex method. It is used by the module plain for automatic sizing of pictures.

math
This package extends Asymptote's mathematical capabilities with point-in-polygon and intersection algorithms and matrix arithmetic.

aCos aSin aTan Cos cot csc determinant drawline extension frac grid interpolate node nonsquare normal partialsum quadrant radians rectangular sec Sin slope square square2 square3 Tan unitnormal value zero zeta

geometry
This module provides the beginnings of a geometry package. It currently includes a triangle structure and functions to draw interior arcs of triangles and perpendicular symbols.

see http://svn.sourceforge.net/viewvc/asymptote/trunk/asymptote/base/geometry.asy?revision=1629&view=markup

perpendicular square

stats
This package implements a Gaussian random number generator and a collection of statistics routines, including histogram and leastsquares.

Gaussian Gaussrand Gaussrandpair frequency halfbox histogram kurtosis kurtosisexcess leastsquares mean rms skewness stdev unitrand variance variancebiased

patterns
This package implements Postscript tiling patterns and includes several convenient pattern generation routines.

brick checker crosshatch hatch tile tiling

tree
This package implements an example of a dynamic binary search tree.

contains lookup newtree

drawtree
This is a simple tree drawing module.

drawAll layout makeNode

feynman
This package is useful for drawing Feynman diagrams.

currentarrow currentmomarrow do_overpaint drawDoubleLine drawFermion drawGhost drawGluon drawMomArrow drawPhoton drawScalar drawVertex drawVertexBox drawVertexBoxO drawVertexBoxX drawVertexO drawVertexOX drawVertexTriangle drawVertexTriangleO drawVertexX fmdefaults gluon momArrowPath momarrowsize photon texshipout

roundedpath
This package is useful for rounding the sharp corners of paths.

roundedpath

pdfanim
This module produces portable clickable high-quality PDF movies.

embed
This module provides an interface to the LaTeX package for embedding movies, sounds, and 3D objects into a PDF document.

embed hyperlink

slide
This package provides a simple yet high-quality facility for making presentation slides, including portable embedded PDF animations.

background center checkposition equation figure incrementposition item newslide nextpage numberpage outline remark skip step subitem title titlepage vbox

MetaPost
This package provides some useful routines to help MetaPost users migrate old MetaPost code to Asymptote.

cutafter cutbefore

unicode
Import this package at the beginning of the file to instruct LaTeX to accept unicode (UTF-8) standardized international characters.

latin1
If you don't have LaTeX support for unicode installed, you can enable support for Western European languages (ISO 8859-1) by importing the module latin1.

babel
This module implements the LaTeX babel package in Asymptote.

babel

annotate
This module supports PDF annotations for viewing with Adobe Reader.

CAD
This package provides basic pen definitions and measurement functions for simple 2D CAD drawings according to DIN 15.

graph
This package implements two-dimensional linear and logarithmic graphs, including automatic scale and tick selection.

Arc Bottom BottomTop Broken Circle Format Left LeftRight LeftTicks Linear Log LogFormat NoTicks Right RightTicks Scale Spline Straight Ticks Top XEquals XZero YEquals YZero autoscale axes axis axiscoverage bool bounds checkaxis conditional crop divisors drawtick errorbar errorbars graph join labelaxis labeltick labelx labely limits linear logaxiscoverage next polargraph scientific secondaryX secondaryY tick tickMax tickMin ticklabel ticklabelshift ticklocate ticks upscale valuetime vector vectorfield - Draw a vectorfield along a path xaxis xaxisAt xequals xlimits xtick yaxis yaxisAt yequals ylimits ytick

palette
Automatic BWRainbow BWRainbow2 Full Grayscale PaletteTicks Rainbow Range data) palette range transpose

three
This module fully extends the notion of guides and paths in Asymptote to three dimensions.

acos1 aim alias aspect bbox3 cast concat controls copy curl3 cycle3 distort init intersection invert lookAt nodes nullpath3 oblique obliqueX obliqueY obliqueZ orthographic perspective plane project projection scale3 spec split splitCubic tension3 theta void xscale3 xypart yscale3 zscale3

light
Provides a simple implementation of three-dimensional lighting effects.

defaultshade defaultshading light shade

graph3
Implements three-dimensional versions of the functions in the graph module.

G Spline Straight autolimits dir graph graph3 join perpendicular phi polargraph projecttime surface v xcrop ycrop zaxis zcrop zlimits

solids
Defines a structure revolution that can be used to fill and draw surfaces of revolution.

base cone cylinder perp revolution sphere tangent

surfaces
Package for drawing Bézier surfaces, the natural two-dimensional generalizations of a Bézier curve.

featpost3D (obsolete)
aCos angline anglinen aSin aTan bracket bstr cartaxes cb circleshadowpath coarse_line conorm Cos cot cover crossingpoint crossingpointf csc cstr determinant director_invisible doitnow draw_all_test draw_invisible drawline drawsegment ellipticpath ellipticshadowpath emptyline extension face face_drawfill face_invisible facepath faceraytrace faceshadowpath fieldlinepath fieldlinestep fill_faces fillfacewithlight flip frac generatedirface generatedirline generateonebiax getangle getanglepair getcossine getready goodcirclepath grid head_on_circle hexagonaltrimesh insidedge insidethisface insidethistriangle insideviewsphere insideviewtriangle interpolate kindofcube lineraytrace LinFunc magnetictrajectorypath makeface makeline masscenter maycrossviewplan maycrossviewplanf N ncrossprod nDotprod node nonsquare normal parSurFunc partialsum partrimesh pathofstraightline positivecharge produce_vga_border projectpoint ps quadrant radians rectangular resolvec rigorouscircle rigorouscone rigorousdisc rigorousfearpath rigorousfearshadowpath rp sec setthearena setthestage sharpraytrace signalshadowvertex signalvertex simplecar Sin slope smoothtorus spatialhalfcircle spatialhalfsfear square square2 square3 squareangline SurFunc Tan tdarrow themarkisinview trajectorypath tropicalglobe twocyclestogether unitnormal value VecFunc verygoodcone whatisthis X Z zero zeta

flowchart
Provides routines to assist in drawing flowcharts.

bevel diamond path rectangle roundrectangle

contour
This package draws contour lines.

addseg case1 case2 case3 checktriangle contour join

slopefield
curve func slopefield

Other Reference
File input and output

title: Asymptote


text:
Talk:Music Theory/Rhythm

This article is horrible. Since when are eighth notes "Uncommon"? I'm a full time Music student, so I will try and help improve this when I get a chance, but I won't have too much time. I'll need to make an account first though... (Owen) The small hours of the morning, 25th November 2007

And an arsis would be what exactly? Same goes for thesis....ok a conductor goes down on one and up on the other...what's the significance? Is it just an arbitrary convention or are the terms descriptive of something that is causal of the conductor's up/down preferences? Maybe I'm just stupid or something, but everything about the 'sub-beats' is incomprehensible to me....have those contributing considered running it by someone who doesn't understand music/music theory, and plays no instrument because I'm thinking maybe the text makes sense only to those who already understand what it is supposed to explain...?

 * Since you are self professed as to not understanding music, would you be willing to continue to ask the sorts of questions you've already asked, or would it be too frustrating of a venture for you (which is understandable)? -- Jason C Daniels 23:36, 2 April 2007 (UTC)

 * Also, since you've got no "official" understanding of music theory, are you willing to accept as valid, a Wikibook that links to the more elementary concepts for which the author assumes the reader has knowledge? -- Jason C Daniels 23:36, 2 April 2007 (UTC)

Wouldn't it be wise to include African and world rhythm systems, along with the classical rhythm system?

 * I agree that some discussion of this is warranted for a detailed understanding of rhythm. However, the originator of the book states an intent to cover western styles of music. So the question to the modules author is: "Is this the proper module for a discussion on African and other non-western rhythms?" -- Jason C Daniels 23:36, 2 April 2007 (UTC)

This is horribly written and also completely wrong in places... the author obviously has no clue of the difference between simple and compound; and duple triple and quadruple. I want to give anyone the chance to discuss it first before editing it however... --Ross angus 02:34, 28 February 2007 (UTC)

 * Please rephrase your concerns in a manner that follows the etiquette standards for Wikibooks. Also, please provide the correct information for the points where the author is mistaken. -- Jason C Daniels 23:36, 2 April 2007 (UTC)

I would like to participate in improving the quality of the book. However, before I do, I have some requests of those who also seem to want the same.

 * When engaging in discussion, follow the rules of etiquette outlined for Wikibooks.

 * When you have better knowledge than what is currently in the book, please either make the edits when it is clear that no one will be mad, or post your proposed edits here on the discussion page.

 * Regardless if cited within module for the book, when there is dispute over a fact, lets be professional and bring relevant sources to the table. It may be that there is a legitimate dispute in the industry.  It may be that someone misread an article.  Unless we have the same information to work from it is unlikely that the dispute will ever be resolved.

-- Jason C Daniels 22:53, 2 April 2007 (UTC)
 * Please sign your comments. It's difficult, though not impossible, to discuss items with anonymous parties.

I propose that when discussing how to change this module, that we break our conversations off into two major categories, and further subcategories as needed. The two major discussion categories that I propose are listed below. Please provide feedback on my suggestions. -- Jason C Daniels 23:12, 2 April 2007 (UTC)

 * Module Content Discussion.
 * This category of discussion will encompass all things content related. The list includes but should not be limited to technical accuracy, grammar and spelling, proposals for adding or removing specific verbiage, images, or other content. This is where sources should be cited.  I expect this to be the area where most discussion happens in the early part of a modules development. -- Jason C Daniels 23:12, 2 April 2007 (UTC)

 * Module Format Discussion.
 * This category will contain discussions pertinent only to presenting the information contained within the module. My initial gut feel on viable subjects for format include:  If the content and title of the section are reflective of each other.  "Copy Editor" type discussions such as if it appropriate to rearrange certain words, phrases, sentences or paragraphs; if the language used is the best to convey the intended meaning, for the intended audience...etc  I expect this to be where most discussion happens when as a module reaches maturity. -- Jason C Daniels 23:12, 2 April 2007 (UTC)

title: Talk:Music Theory/Rhythm


text:
User talk:FrankLambert

Who screws up one's User talk page?!
On 7/6, this talk page was 1.5 printout pages long. Today, 7/9 the page 'doesn't exist yet. To create the page, start typing ..."!

Well, it does exist, has existed and will continue until the next jerk deletes it!

I believe in "non illegitimi carborundum' and not ever being carborundified when not justified :-) FrankLambert 15:37, 9 July 2006 (UTC)

 * I do not see this page listed in the deletion log. Perhaps you are referring to your user page? --hagindaz 18:02, 9 July 2006 (UTC)

Reverting pages
Hi! Here's a hint that I'm sure will improve your Wikibooks experience. All revisions of a page are stored on the server, and you can revert back to any previous version. Here's how you do it (from w:Help:Reverting): Thank you for spending so much time writing content. Don't worry so much about formatting - others will eventually improve it. Knowledgeable writers are a lot more valuable, so I hope to format many more contributions from you. :) --hagindaz 23:41, 12 July 2006 (UTC)
 * Go to the page you wish to revert, click on the History tab at the top of the page, then click on the time and date of the earlier version you want to revert to. It will not work if you click on 'cur', 'last', or "Compare selected versions".
 * When the page displays, text similar to this: (Revision as of 23:19 Jul 15, 2003), will display. It appears below the page's title, in place of the From {project name}, usually seen.
 * Verify that you've selected the correct version, then click a link to edit the page as you would normally.
 * You'll get a warning, above the edit box, about editing an out-of-date revision.
 * Ignore the warning and save the page. Be sure to add the word "revert" (or "rv") to the edit summary, along with a short explanation if not obvious.

Wikipedia
I am not very familiar with Wikipedia's policies, but the external links policy is at w:Wikipedia:External links. If the link doesn't violate the policy, then you should talk to w:User:Nonsuch. If that doesn't work and you want to pursue the issue, see w:Wikipedia:Resolving disputes. Sorry I can't help you further, but Wikipedia is a separate project with its own policies. --hagindaz 06:30, 17 July 2006 (UTC)

title: User talk:FrankLambert


text:
User talk:Dawn Marie Schaussen

Please don't vandalise. This is your final warning. --Dragontamer 15:51, 9 July 2006 (UTC)

title: User talk:Dawn Marie Schaussen