-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchapter3.html
More file actions
35 lines (34 loc) · 54.8 KB
/
chapter3.html
File metadata and controls
35 lines (34 loc) · 54.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE html>
<html>
<head>
<title>L.B.Stanza</title>
<link type="text/css" rel="stylesheet" href="resources/mainstyle.css">
<link type="text/css" rel="stylesheet" href="resources/documentation.css">
</head>
<body>
<table class="wrap">
<tr><td colspan="3" class="banner">
<a href="index.html">Home</a><a href="stanzabyexample.html">Table of Contents</a><a href="chapter2.html">Previous Chapter</a><a href="chapter4.html">Next Chapter</a>
</td></tr>
<tr>
<td class="nav">
<h1>NAVIGATION</h1>
<h2><a href="#anchor186">The Less Basic</a></h2><h3><a href="#anchor23">More about Structs</a></h3><h4><a href="#anchor187">Mutable Fields</a></h4><h4><a href="#anchor188">Providing Custom Printing Behaviour</a></h4><h3><a href="#anchor24">The Match Expression</a></h3><h4><a href="#anchor189">General Form</a></h4><h4><a href="#anchor190">Name Shadowing</a></h4><h4><a href="#anchor191">Matching Multiple Arguments</a></h4><h4><a href="#anchor192">Example: Cats and Dogs</a></h4><h4><a href="#anchor193">Introducing Union Types</a></h4><h4><a href="#anchor194">Branches with Unspecified Types</a></h4><h4><a href="#anchor195">Revisiting the If Expression</a></h4><h3><a href="#anchor25">The Is Expression</a></h3><h3><a href="#anchor26">Casts</a></h3><h3><a href="#anchor27">Deep Casts</a></h3><h4><a href="#anchor196">Types as Contracts</a></h4><h3><a href="#anchor28">Operations on Strings</a></h3><h4><a href="#anchor197">Length</a></h4><h4><a href="#anchor198">Retrieve Character</a></h4><h4><a href="#anchor199">Convert to String</a></h4><h4><a href="#anchor200">Append</a></h4><h4><a href="#anchor201">Substring</a></h4><h3><a href="#anchor29">Operations on Tuples</a></h3><h4><a href="#anchor202">Length</a></h4><h4><a href="#anchor203">Retrieve an Element</a></h4><h4><a href="#anchor204">Tuples of Unknown Length</a></h4><h3><a href="#anchor30">Packages</a></h3><h4><a href="#anchor205">Importing Packages</a></h4><h4><a href="#anchor206">Public Visibility</a></h4><h4><a href="#anchor207">Private Visibility</a></h4><h3><a href="#anchor31">Function Overloading</a></h3><h3><a href="#anchor32">Operator Mapping</a></h3><h4><a href="#anchor208">Operator Overloading</a></h4><h4><a href="#anchor209">Get and Set</a></h4><h3><a href="#anchor33">Vectors</a></h3><h3><a href="#anchor34">HashTables</a></h3><h4><a href="#anchor210">Creation</a></h4><h4><a href="#anchor211">Set</a></h4><h4><a href="#anchor212">Get</a></h4><h4><a href="#anchor213">Does a Key Exist?</a></h4><h4><a href="#anchor214">Default Values</a></h4><h3><a href="#anchor35">KeyValue Pairs</a></h3><h3><a href="#anchor36">For Loops over Sequences</a></h3><h4><a href="#anchor215">General Form</a></h4><h4><a href="#anchor216">Examples of Collections</a></h4><h3><a href="#anchor37">Extended Example: Complex Number Package</a></h3><h4><a href="#anchor217">The Complex Package</a></h4><h4><a href="#anchor218">Printing Complex Numbers</a></h4><h4><a href="#anchor219">Main Driver</a></h4><h4><a href="#anchor220">Arithmetic Operations</a></h4><h4><a href="#anchor221">Root Finding</a></h4><h4><a href="#anchor222">Find all the Roots!</a></h4>
</td>
<td class="main">
<h1 id="anchor186">The Less Basic</h1><p></p><h2 id="anchor23">More about Structs</h2><p></p><h3 id="anchor187">Mutable Fields</h3><p>In the last chapter, you were taught how to define structs and create objects. But the structs you created were <span style="font-style:italic;">immutable</span>. You couldn't change the objects at all after you created them. </p><p>Here was our original definition of <code>Dog</code>. </p><pre><code>defstruct Dog :<br> name: String<br> breed: String</code></pre><p>We can create a dog by calling the <code>Dog</code> function with a provided name and breed. But once created, you cannot change a dog's name or breed. Here's how to define <code>Dog</code> with a <span style="font-style:italic;">setter function</span> for changing its name.</p><pre><code>defstruct Dog :<br> name: String with: (setter => set-name)<br> breed: String</code></pre><p>Now we can use the <code>set-name</code> function to change a dog's name.</p><pre><code>val d = Dog("Shadow", "Golden Retriever")<br>println("I used to be called %_." % [name(d)])<br>set-name(d, "Sir Shadow the Wise")<br>println("But now I am called %_." % [name(d)])</code></pre><p>prints out</p><pre><code>I used to be called Shadow.<br>But now I am called Sir Shadow the Wise.</code></pre><p>With the above definition of <code>Dog</code>, we can change a dog's name but not its breed. If we want to be able to change the breed as well then we need to similarly give it a setter function. </p><p>The convention is to call the setter function the same name as the field it's setting but with a <code>set-</code> prefix. Follow this convention unless you have a good reason not to.</p><h3 id="anchor188">Providing Custom Printing Behaviour</h3><p>We are used to using the <code>print</code> and <code>println</code> functions for printing things. Almost all of Stanza's core types can be printed using <code>print</code>. But <code>print</code> doesn't yet know how to print <code>Dog</code> objects. So the following</p><pre><code>val d = Dog("Shadow", "Golden Retriever")<br>println("They call me %_." % [d])</code></pre><p>prints out the fairly useless message</p><pre><code>They call me [Unprintable Object].</code></pre><p>Here is how to provide custom printing behaviour for <code>Dog</code> objects.</p><pre><code>defmethod print (o:OutputStream, d:Dog) :<br> print(o, "%_ the %_." % [name(d), breed(d)])</code></pre><p>Now the same code</p><pre><code>val d = Dog("Shadow", "Golden Retriever")<br>println("They call me %_." % [d])</code></pre><p>prints out</p><pre><code>They call me Shadow the Golden Retriever.</code></pre><p>The <code>defmethod</code> keyword <span style="font-style:italic;">extends</span> a defined <span style="font-style:italic;">multi</span> with a new <span style="font-style:italic;">method</span>. We'll learn what that all means later. This gives you small taste of Stanza's multimethod functionality and is the basis for Stanza's class-less object system. </p><p>In the body of the <code>print</code> method</p><pre><code>print(o, "%_ the %_." % [name(d), breed(d)])</code></pre><p>be especially mindful of the <code>o</code> argument to <code>print</code>. This argument says to print the message to the <code>o</code> <span style="font-style:italic;">output stream</span>.</p><h2 id="anchor24">The Match Expression</h2><p>Now that you are familiar with a number of different types and know how to create objects of each one, you'll have to learn how to differentiate between them. </p><p>Here's how to write a function that does different things depending on whether its argument is an integer or a string.</p><pre><code>defn what-am-i (x) :<br> match(x) :<br> (i:Int) : println("I am %_. I am an integer." % [i])<br> (s:String) : println("I am %_. I am a string." % [s])</code></pre><p>If we call it with an integer</p><pre><code>what-am-i(42)</code></pre><p>then it prints out</p><pre><code>I am 42. I am an integer.</code></pre><p>But if we call it with a string</p><pre><code>what-am-i("Timon")</code></pre><p>then it prints out</p><pre><code>I am Timon. I am a string.</code></pre><p>If we call it with neither an integer or a string</p><pre><code>what-am-i(false)</code></pre><p>then the program crashes.</p><pre><code>FATAL ERROR: No matching branch.<br> at stanzaproject/lessbasic.stanza:5.9<br> at stanzaproject/lessbasic.stanza:9.0</code></pre><h3 id="anchor189">General Form</h3><p>Here's the general form of a match expression.</p><pre><code>match(argument expressions ...) :<br> (argname:ArgType ...) : body<br> ...</code></pre><p>A match expression</p><ol><li>computes the result of evaluating all the argument expressions,
</li><li>then tests to see whether the results match the argument types indicated in the first branch.
</li><li>If the types match, then the branch argument names are <span style="font-style:italic;">bound</span> to the results, and the branch body is evaluated. The result of the branch is the result of the entire match expression.
</li><li>If the types do not match, then the subsequent branch is tried. This continues either until a branch finally matches, or no branch matches and the program crashes.
</li></ol><h3 id="anchor190">Name Shadowing</h3><p>The match expression branches each start a new scope, and the branch arguments are only visible from within that scope. To avoid confusing you we gave new names (<code>i</code> and <code>s</code>) to the branch arguments in our example</p><pre><code>defn what-am-i (x) :<br> match(x) :<br> (i:Int) : println("I am %_. I am an integer." % [i])<br> (s:String) : println("I am %_. I am a string." % [s])</code></pre><p>but you can really use any name for the branch arguments. In fact, it is common to use the same name as the value that you are matching on.</p><pre><code>defn what-am-i (x) :<br> match(x) :<br> (x:Int) : println("I am %_. I am an integer." % [x])<br> (x:String) : println("I am %_. I am a string." % [x])</code></pre><h3 id="anchor191">Matching Multiple Arguments</h3><p>The match expression supports matching against <span style="font-style:italic;">multiple</span> arguments. Here's a function that returns different things depending on the types of both of its arguments.</p><pre><code>defn differentiate (x, y) :<br> match(x, y) :<br> (x:Int, y:Int) : 0<br> (x:Int, y:String) : 1<br> (x:String, y:Int) : 2<br> (x:String, y:String) : 3</code></pre><p>If we call it with different combinations of integers and strings</p><pre><code>println(differentiate(42, 42))<br>println(differentiate(42, "Timon"))<br>println(differentiate("Pumbaa", 42))<br>println(differentiate("Timon", "Pumbaa"))</code></pre><p>it returns different results for each. The above prints out</p><pre><code>0<br>1<br>2<br>3</code></pre><h3 id="anchor192">Example: Cats and Dogs</h3><p>Here's a definition of two structs, <code>Cat</code> and <code>Dog</code>. </p><pre><code>defstruct Dog : (name:String)<br>defstruct Cat : (name:String)</code></pre><p>Here's the definition of a <code>say-hi</code> function that prints different messages depending on whether <code>x</code> is a <code>Cat</code> or <code>Dog</code>. </p><pre><code>defn say-hi (x) :<br> match(x) :<br> (x:Dog) : println("Woof says %_ the dog." % [name(x)])<br> (x:Cat) : println("Meow says %_ the cat." % [name(x)])</code></pre><p>Let's call it a few times. </p><pre><code>say-hi(Dog("Shadow"))<br>say-hi(Dog("Chance"))<br>say-hi(Cat("Sassy"))</code></pre><p>prints out</p><pre><code>Woof says Shadow the dog.<br>Woof says Chance the dog.<br>Meow says Sassy the cat.</code></pre><h3 id="anchor193">Introducing Union Types</h3><p>One problem with the <code>say-hi</code> function is that it allows us to pass obviously incorrect arguments to it, which crashes the program.</p><pre><code>say-hi(42)</code></pre><p>results in</p><pre><code>FATAL ERROR: No matching branch.<br> at stanzaproject/lessbasic.stanza:5.9<br> at stanzaproject/lessbasic.stanza:9.0</code></pre><p>This is because we didn't give <code>x</code> a type annotation</p><pre><code>defn say-hi (x)</code></pre><p>which we've said is equivalent to declaring it with the <code>?</code> type.</p><pre><code>defn say-hi (x:?)</code></pre><p>The <code>?</code> type, by definition, allows us to pass anything to it, so Stanza is doing what it should, even though it's not what we want.</p><p>We would like to give <code>x</code> a type annotation that prevents us from passing <code>42</code> to <code>say-hi</code>, but what should it be? It's neither <code>Dog</code> nor <code>Cat</code> because <code>say-hi</code> has to accept them both. The solution is to annotate <code>say-hi</code> to take <span style="font-style:italic;">either</span> a <code>Dog</code> <span style="font-style:italic;">or</span> a <code>Cat</code>. </p><pre><code>defn say-hi (x:Dog|Cat) :<br> match(x) :<br> (x:Dog) : println("Woof says %_ the dog." % [name(x)])<br> (x:Cat) : println("Meow says %_ the cat." % [name(x)])</code></pre><p>You can verify that calling <code>say-hi</code> with dogs and cats continue to work, but more importantly, that calling <code>say-hi</code> with <code>42</code> <span style="font-style:italic;">doesn't</span> work. Attempting to compile</p><pre><code>say-hi(42)</code></pre><p>gives the error</p><pre><code>Cannot call function say-hi of type Cat|Dog -> False with arguments of type (Int).</code></pre><p><code>Cat|Dog</code> is an example of a <span style="font-style:italic;">union type</span>. Union types allow us to specify the concept of "either this type or that type". </p><h3 id="anchor194">Branches with Unspecified Types</h3><p>If you leave off the type annotation for an argument in a match expression branch, then Stanza will automatically infer it to have the same type as the match argument expression. The following</p><pre><code>defn f (x:Int|String) :<br> match(x) :<br> (x:Int) : body<br> (x) : body2</code></pre><p>is equivalent to</p><pre><code>defn f (x:Int|String) :<br> match(x) :<br> (x:Int) : body<br> (x:Int|String) : body2</code></pre><p>This is often used to provide a default branch to run when none of the preceeding branches match.</p><h3 id="anchor195">Revisiting the If Expression</h3><p>Now that you've been introduced to the match expression, it's time to unveil the inner workings of the if expression. It turns out that the if expression is just a slightly decorated match expression.</p><pre><code>if x < 4 :<br> println("Do this")<br>else :<br> println("Do that")</code></pre><p>is completely equivalent to</p><pre><code>match(x < 4) :<br> (p:True) : println("Do this")<br> (p:False) : println("Do that")</code></pre><p>The if expression is an example of a simple <span style="font-style:italic;">macro</span>. Macros are very powerful tools for simplifying the syntax of commonly used patterns. Stanza includes many constructs that are simply decorated versions of other constructs, each implemented as a macro. The defstruct statement is another example. Later, we'll learn how to write our own macros to provide custom syntax for common patterns.</p><h2 id="anchor25">The Is Expression</h2><p>Often you simply want to determine whether an object is of a certain type. Here is a long-winded method for checking whether <code>x</code> is a <code>Dog</code> object or not.</p><pre><code>val dog? = match(x) :<br> (x:Dog) : true<br> (x) : false</code></pre><p>Because this operation is so common, Stanza provides a shorthand for it. The above can be rewritten equivalently as</p><pre><code>val dog? = x is Dog</code></pre><p>Here is the general form.</p><pre><code>exp is Type</code></pre><p>It first evaluates <code>exp</code> and then returns <code>true</code> if the result is of type <code>Type</code>. Otherwise it returns <code>false</code>. The is expression is another example of a convenience syntax implemented using a macro. As you've noticed by now, Stanza's core library makes heavy use of macros.</p><p>The negative form of the is expression is the is-not expression. The following determines whether <code>x</code> is <span style="font-style:italic;">not</span> a type of <code>Dog</code>.</p><pre><code>val not-dog? = x is-not Dog</code></pre><h2 id="anchor26">Casts</h2><p>Stanza's type system is designed primarily to be <span style="font-style:italic;">predictable</span>, not necessarily smart. This means that, as the programmer, you will often be able to infer a more specific type for an object than Stanza. Here is an example.</p><pre><code>defn meow (x:Cat) :<br> println("Meow!!!")<br> <br>defn f (x:Cat|Dog) :<br> val catness = if x is Cat : 1 else : -1<br> if catness > 0 :<br> meow(x)</code></pre><p>Attempting to compile the above gives the error</p><pre><code>Cannot call function meow of type Cat -> False with arguments of type (Dog|Cat).</code></pre><p>Stanza believes that <code>x</code> is a <code>Dog|Cat</code>, but from our reasoning, the only way that <code>meow</code> can be called is if <code>catness</code> is positive. And <code>catness</code> is only positive if <code>x</code> is a <code>Cat</code>. Therefore <code>x</code> must be a <code>Cat</code> in the call to <code>meow</code> and the code should be fine.</p><p>To force Stanza to accept <code>x</code> as a <code>Cat</code>, we can explicitly <span style="font-style:italic;">cast</span> <code>x</code>.</p><pre><code>defn f (x:Cat|Dog) :<br> val catness = if x is Cat : 1 else : -1<br> if catness > 0 :<br> meow(x as Cat)</code></pre><p>The cast tells Stanza to trust your assertion that <code>x</code> is indeed a <code>Cat</code>. If, for some reason, your reasoning is faulty and <code>x</code> turns out not to be a <code>Cat</code>, then the incorrect cast will cause the program to crash at that point.</p><h2 id="anchor27">Deep Casts</h2><p>Stanza's cast mechanism is much more flexible than many other languages, and, in particular, supports the notion of a <span style="font-style:italic;">deep cast</span>. </p><p>Here is a function that takes an array of integers or strings, and replaces each string in the array with its length.</p><pre><code>defn compute-lengths (xs:Array<Int|String>) :<br> for i in 0 to length(xs) do :<br> match(xs[i]) :<br> (x:String) : xs[i] = length(x)<br> (x:Int) : false</code></pre><p>And here is a function that computes the sum of an array of integers.</p><pre><code>defn sum-integers (xs:Array<Int>) :<br> var sum = 0<br> for i in 0 to length(xs) do :<br> sum = sum + xs[i]<br> sum </code></pre><p>Now, given an array containing both integers and strings, we want to first replace each string with its length, and then compute the sum of the integers in the array.</p><pre><code>val xs = Array<Int|String>(4)<br>xs[0] = 42<br>xs[1] = 7<br>xs[2] = "Timon"<br>xs[3] = "Pumbaa"<br><br>compute-lengths(xs)<br>sum-integers(xs)</code></pre><p>Attempting to compile the above gives us the error</p><pre><code>Cannot call function sum-integers of type Array<Int> -> Int with arguments <br>of type (Array<String|Int>).</code></pre><p>Stanza is complaining that <code>sum-integers</code> requires an array of integers, so <code>xs</code> is an illegal argument as it might contain strings. </p><p>But <span style="font-style:italic;">we</span> know that <code>xs</code> will not contain any strings at that point because <code>compute-lengths</code> replaced all of them with their lengths. So we can use a cast to force Stanza to trust this assertion.</p><pre><code>sum-integers(xs as Array<Int>)</code></pre><p>With the above correction, the program now compiles and runs correctly.</p><h3 id="anchor196">Types as Contracts</h3><p>The above was an example of a <span style="font-style:italic;">deep</span> cast, because it wasn't a direct assertion about the type of <code>xs</code>, but about the types of the objects it <span style="font-style:italic;">contains</span>. You might be wondering, then, what exactly does that cast do? Does it iterate through the array and check every element to see if it is an <code>Int</code>? You'll be relieved to hear that it does not. That would be hopelessly inefficient, and also impossible in general. </p><p>To answer the question, let's investigate what the cast does in the case that we're wrong. Change the definition of <code>compute-lengths</code> to this.</p><pre><code>defn compute-lengths (xs:Array<Int|String>) :<br> for i in 0 to length(xs) - 1 do :<br> match(xs[i]) :<br> (x:String) : xs[i] = length(x)<br> (x:Int) : false</code></pre><p>It now forgets to check the last element. So even after the call to <code>compute-lengths</code>, <code>xs</code> still contains one last string (<code>"Pumbaa"</code>) at the end, and thus our cast is incorrect.</p><p>Compile and run the program. It should crash with this error.</p><pre><code>FATAL ERROR: Cannot cast value to type.<br> at core/core.stanza:3062.16<br> at stanzaprojects/lessbasic.stanza:13.18<br> at core/core.stanza:2292.9<br> at core/core.stanza:4042.16<br> at stanzaprojects/lessbasic.stanza:12.28<br> at stanzaprojects/lessbasic.stanza:23.0</code></pre><p>The file position <code>stanzaprojects/lessbasic.stanza:13.18</code> tells us that the error occurred in the reference to <code>xs[i]</code> in <code>sum-integers</code>. Stanza is saying that it was expecting <code>xs[i]</code> to be an <code>Int</code> because you promised that <code>xs</code> is an <code>Array<Int></code>. But <code>xs[i]</code> is <span style="font-style:italic;">not</span> an <code>Int</code>, and so your program is wrong.</p><p>In general, a value's type in Stanza does not directly say what it <span style="font-style:italic;">is</span>. Instead, a value's type is a <span style="font-style:italic;">contract</span> on how it should behave. Part of the contract for an <code>Array<Int></code> is that it should only contain <code>Int</code> objects. The above program crashed as soon as Stanza determined that <code>xs</code> does not satisfy its contract. </p><h2 id="anchor28">Operations on Strings</h2><p>There are many useful operations on <code>String</code> objects available in the core library. We'll show a few of them here.</p><h3 id="anchor197">Length</h3><p>Here's how to obtain the length of a string.</p><pre><code>val s = "Hello World"<br>length(s)</code></pre><h3 id="anchor198">Retrieve Character</h3><p>Here's how to retrieve a given character in a string.</p><pre><code>val s = "Hello World"<br>s[4]</code></pre><p>The first character has index 0, and the last character is indexed one less than the length of the string. There is no function for setting the character in a string because strings are <span style="font-style:italic;">immutable</span> in Stanza. </p><h3 id="anchor199">Convert to String</h3><p>Here's how to convert any object into a string.</p><pre><code>to-string(42)</code></pre><h3 id="anchor200">Append</h3><p>Here's how to form a longer string from appending two strings together.</p><pre><code>val s1 = "Hello "<br>val s2 = "World"<br>append(s1, s2)</code></pre><h3 id="anchor201">Substring</h3><p>Here's how to retrieve a range of characters within a string.</p><pre><code>val str = "Hello World"<br>println(str[4 to 9])</code></pre><p>prints out</p><pre><code>o Wor</code></pre><p>It's all the characters between index 4 (inclusive) and index 9 (exclusive) in the string.</p><p>If we wanted to include the ending index, then we can use the <code>through</code> keyword, just as we've learned from the previous chapter.</p><pre><code>println(str[4 through 9])</code></pre><p>prints out</p><pre><code>o Worl</code></pre><p>If we wanted to extract all characters from index 4 until the end of the string, we can use <code>false</code> as the ending index.</p><pre><code>println(str[4 to false])</code></pre><p>prints out</p><pre><code>o World</code></pre><p>Check out the reference documentation for a listing of operations supported by <code>String</code> objects.</p><h2 id="anchor29">Operations on Tuples</h2><p>Tuples support a few additional operations for querying its properties.</p><h3 id="anchor202">Length</h3><p>Here is how to retrieve the length of a tuple.</p><pre><code>val t = [4, 42, "Hello"]<br>length(t)</code></pre><h3 id="anchor203">Retrieve an Element</h3><p>Here is how to retrieve an element in a tuple at a <span style="font-style:italic;">dynamically</span> calculated index.</p><pre><code>val t = [4, 42, "Hello"]<br>val i = 1 + 1<br>println(t[i])</code></pre><p>prints out</p><pre><code>Hello</code></pre><p>Note that, in general, a dynamically calculated index is not known until the program actually runs. This means that Stanza does not try to determine a precise type for the result of <code>t[i]</code>. The resulting type of <code>t[i]</code> is the union of all the element types in the tuple.</p><p>Attempting to compile this</p><pre><code>val t = [4, 42, "Hello"]<br>val x:Int = t[0 + 1]</code></pre><p>results in the error</p><pre><code>Cannot assign expression of type Int|String to value x with declared type Int.</code></pre><p>The tuple <code>t</code> has type <code>[Int, Int, String]</code>, and so an arbitrary element at an unknown index has type <code>Int|String</code>. </p><p>To overcome this, you may explicitly cast the result to an <code>Int</code> yourself. </p><pre><code>val t = [4, 42, "Hello"]<br>val x:Int = t[0 + 1] as Int</code></pre><p>Check out the reference documentation for a listing of operations supported by tuples.</p><h3 id="anchor204">Tuples of Unknown Length</h3><p>The type <code>[Int]</code> is a tuple containing one integer, and the type <code>[Int, Int]</code> is a tuple containing two integers, et cetera. But what if we want to write a function that takes a tuple of <span style="font-style:italic;">any</span> number of integers?</p><p>Here is a function that prints out every number in a tuple of integers.</p><pre><code>defn print-tuple (t:Tuple<Int>) :<br> for i in 0 to length(t) do :<br> println(t[i])</code></pre><p>The following</p><pre><code>print-tuple([1, 2, 3])</code></pre><p>prints out</p><pre><code>1<br>2<br>3</code></pre><p>But the following</p><pre><code>print-tuple([1, "Timon"])</code></pre><p>fails to compile with the error</p><pre><code>Cannot call function print-tuple of type Tuple<Int> -> False with arguments<br>of type ([Int, String]).</code></pre><p>In general, the type <code>Tuple<Type></code> represents a tuple of unknown length where each element type is of type <code>Type</code>. </p><h2 id="anchor30">Packages</h2><p>Thus far, all of your code has been contained in a single package. When your projects get larger, you'll start to feel the need to split up the entire program into smaller isolated components. In Stanza, you would do this by partitioning your program into multiple <span style="font-style:italic;">packages</span>. </p><p>Create a separate file called <code>animals.stanza</code> containing</p><pre><code>defpackage animals :<br> import core<br><br>defstruct Dog :<br> name: String<br>defstruct Cat :<br> name: String<br><br>defn sound (x:Dog|Cat) :<br> match(x) :<br> (x:Dog) : "woof"<br> (x:Cat) : "meow"</code></pre><p>The <code>animals</code> package contains all of our code for handling dogs and cats. It contains the struct definitions for <code>Dog</code> and <code>Cat</code>, as well as the <code>sound</code> function that returns the sound made by each animal.</p><p>Now create a file called <code>mainprogram.stanza</code> containing</p><pre><code>defpackage animal-main :<br> import core<br><br>defn main () :<br> val d = Dog("Shadow")<br> val c = Cat("Sassy")<br> println("My dog %_ goes %_!" % [name(d), sound(d)])<br> println("My cat %_ goes %_!" % [name(c), sound(c)])<br> <br>main()</code></pre><p>The <code>animal-main</code> package contains the main code of the program and it will use the <code>animals</code> package as a library. </p><h3 id="anchor205">Importing Packages</h3><p>Now compile both of your source files by typing in the terminal</p><pre><code>stanza animals.stanza mainprogram.stanza -o animals</code></pre><p>Oops! Something's wrong! Stanza reports these errors.</p><pre><code>mainprogram.stanza:5.11: Could not resolve Dog.<br>mainprogram.stanza:6.11: Could not resolve Cat.<br>mainprogram.stanza:7.44: Could not resolve sound.<br>mainprogram.stanza:8.44: Could not resolve sound.</code></pre><p>The problem is that our <code>animal-main</code> package never <span style="font-style:italic;">imported</span> the <code>animals</code> package. Packages must be imported before they can be used. So change</p><pre><code>defpackage animal-main :<br> import core</code></pre><p>to</p><pre><code>defpackage animal-main :<br> import core<br> import animals</code></pre><p>and try compiling again. Stanza <span style="font-style:italic;">still</span> reports the same errors.</p><pre><code>mainprogram.stanza:5.11: Could not resolve Dog.<br>mainprogram.stanza:6.11: Could not resolve Cat.<br>mainprogram.stanza:7.44: Could not resolve sound.<br>mainprogram.stanza:8.44: Could not resolve sound.</code></pre><h3 id="anchor206">Public Visibility</h3><p>What's going on? The problem now is that our <code>animals</code> package did not make any of its definitions <span style="font-style:italic;">public</span>. By default, definitions are not visible from outside the package it is declared in. To make a definition visible, you must prefix the definition with the <code>public</code> keyword. </p><p>Let's declare our <code>Dog</code> and <code>Cat</code> structs, and the <code>sound</code> function to be publicly visible.</p><pre><code>defpackage animals :<br> import core<br><br>public defstruct Dog :<br> name: String<br>public defstruct Cat :<br> name: String<br><br>public defn sound (x:Dog|Cat) :<br> match(x) :<br> (x:Dog) : "woof"<br> (x:Cat) : "meow"</code></pre><p>Now the program compiles successfully and prints out</p><pre><code>My dog Shadow goes woof!<br>My cat Sassy goes meow!</code></pre><h3 id="anchor207">Private Visibility</h3><p>By default, all definitions are <span style="font-style:italic;">private</span> to the package that they are defined in. There is <span style="font-style:italic;">no</span> way to refer to a private definition from outside the package. This is a very powerful guarantee as it also means that there is no way for any outside code to depend upon the existence of a private definition. </p><p>For example, suppose we rely on a helper function called <code>dog?</code> to help us define the <code>sound</code> function. </p><pre><code>defpackage animals :<br> import core<br><br>public defstruct Dog :<br> name: String<br>public defstruct Cat :<br> name: String<br><br>defn dog? (x:Dog|Cat) :<br> match(x) :<br> (x:Dog) : true<br> (x:Cat) : false<br><br>public defn sound (x:Dog|Cat) :<br> if dog?(x) : "woof"<br> else : "meow"</code></pre><p><code>dog?</code> is private to the <code>animals</code> package, so at any time in the future, if we wanted to rename <code>dog?</code> or remove it, we can safely do so without affecting other code.</p><h2 id="anchor31">Function Overloading</h2><p>By this point, we've learned about arrays, tuples, strings, and how to retrieve the length of each of them.</p><pre><code>val a = Array<Int>(4)<br>val b = "Timon and Pumbaa"<br>val c = [1, 2, 3, 4]<br>length(a) ;Retrieve length of a array<br>length(b) ;Retrieve length of a string<br>length(c) ;Retrieve length of a tuple</code></pre><p>You simply call the <code>length</code> function. Here is what is happening behind the scenes. The <code>core</code> package actually contains <span style="font-style:italic;">many</span> functions called <code>length</code>, but they differ in the type of the argument that they accept. </p><pre><code>defn length (x:Array) -> Int<br>defn length (x:String) -> Int<br>defn length (x:Tuple) -> Int</code></pre><p>When you call <code>length(a)</code>, Stanza automatically figures out which <code>length</code> function you are trying to call based on the type of its argument. <code>a</code> is an array, and so you're obviously trying to call the <code>length</code> function that accepts an <code>Array</code>. No other <code>length</code> function would be legal to call! Similarly, <code>b</code> is a string, so the call to <code>length(b)</code> is obviously a call to the <code>length</code> function that accepts a <code>String</code>. This is a feature called <span style="font-style:italic;">function overloading</span> and is a key part of Stanza's object system. </p><p>Functions can be overloaded based on the number of arguments that they take, and the types of each argument. Let's write our own overloaded function.</p><pre><code>defstruct Dog<br>defstruct Tree<br>defstruct Captain<br><br>defn bark (d:Dog) -> False :<br> println("Woof!")<br>defn bark (t:Tree) -> String :<br> "Furrowed Cork"<br>defn bark (c:Captain) -> False :<br> println("A teeeen-hut!")</code></pre><p>Now let's try calling each of them. The following</p><pre><code>val d = Dog()<br>val t = Tree()<br>val c = Captain()<br>bark(d)<br>println(bark(t))<br>bark(c)</code></pre><p>prints out</p><pre><code>Woof!<br>Furrowed Cork<br>A teeeen-hut!</code></pre><p>Notice that the <code>bark</code> function for <code>Tree</code> returns a <code>String</code>, while the <code>bark</code> functions for <code>Dog</code> and <code>Captain</code> return <code>False</code>. There is no requirement for any of the <code>bark</code> functions to be related or aware of each other. They can even be declared in separate packages! </p><h2 id="anchor32">Operator Mapping</h2><p>In the previous chapter, you were introduced to the basic arithmetic operators. Here we'll show you a bit about how they work underneath. The following</p><pre><code>val a = 13<br>val b = 24<br>a + b<br>a - b<br>a * b<br>a / b<br>a % b<br>(- a)</code></pre><p>can be rewritten equivalently as</p><pre><code>val a = 13<br>val b = 24<br>plus(a, b)<br>minus(a, b)<br>times(a, b)<br>divide(a, b)<br>modulo(a, b)<br>negate(a)</code></pre><p>Thus you can see here that all operators in Stanza are simply syntactic shorthands for specific function calls. Here is a listing of what each operator expands to.</p><pre><code>a + b expands to plus(a, b)<br>a - b expands to minus(a, b)<br>a * b expands to times(a, b)<br>a / b expands to divide(a, b)<br>a % b expands to modulo(a, b)<br>(- x) expands to negate(x)<br><br>a << b expands to shift-left(a, b)<br>a >> b expands to shift-right(a, b)<br>a >>> b expands to arithmetic-shift-right(a, b)<br>a & b expands to bit-and(a, b)<br>a | b expands to bit-or(a, b)<br>a ^ b expands to bit-xor(a, b)<br>(~ x) expands to bit-not(x)<br><br>a == b expands to equal?(a, b)<br>a != b expands to not-equal?(a, b)<br>a < b expands to less?(a, b)<br>a <= b expands to less-eq?(a, b)<br>a > b expands to greater?(a, b)<br>a >= b expands to greater-eq?(a, b)<br>not x expands to complement(x)</code></pre><h3 id="anchor208">Operator Overloading</h3><p>The benefit to mapping each operator to a function call is that you can very easily reuse these operators for your own objects. Here is an example struct definition for modeling points on the cartesian plane.</p><pre><code>defstruct Point :<br> x: Double<br> y: Double</code></pre><p>Next let's define a function called <code>plus</code> that can add together two <code>Point</code> objects.</p><pre><code>defn plus (a:Point, b:Point) :<br> Point(x(a) + x(b), y(a) + y(b))</code></pre><p>Let's try out our function.</p><pre><code>defn main () :<br> val a = plus(Point(1.0,3.0), Point(4.0,5.0))<br> val b = plus(a, Point(7.0,1.0))<br> println("b is (%_, %_)" % [x(b), y(b)])<br><br>main()</code></pre><p>The above prints out</p><pre><code>b is (12.000000000000000, 9.000000000000000)</code></pre><p>But, as mentioned, the <code>+</code> operator is a shorthand for calling the <code>plus</code> function. So our <code>main</code> function can be written more naturally as</p><pre><code>defn main () :<br> val a = Point(1.0,3.0) + Point(4.0,5.0)<br> val b = a + Point(7.0,1.0)<br> println("b is (%_, %_)" % [x(b), y(b)])</code></pre><h3 id="anchor209">Get and Set</h3><p>Two other operators that we have been using without being aware of it are the get and set operators. The following code</p><pre><code>val a = Array<Int>(4)<br>a[0] = 42<br>a[0]</code></pre><p>is equivalent to</p><pre><code>val a = Array<Int>(4)<br>set(a, 0, 42)<br>get(a, 0)</code></pre><p>Thus the <code>a[i]</code> form expands to calls to the <code>get</code> function.</p><pre><code>a[i] expands to get(a, i)<br>a[i, j] expands to get(a, i, j)<br>a[i, j, k] expands to get(a, i, j, k)<br>etc ...</code></pre><p>And the <code>a[i] = v</code> form expands to calls to the <code>set</code> function.</p><pre><code>a[i] = v expands to set(a, i, v)<br>a[i, j] = v expands to set(a, i, j, v)<br>a[i, j, k] = v expands to set(a, i, j, k, v)<br>etc ...</code></pre><h2 id="anchor33">Vectors</h2><p>So far we've only called the library functions in the <code>core</code> package. The <code>collections</code> package contains commonly used datastructures useful for daily programming.</p><p>Here is a program that imports the <code>collections</code> package and creates and prints a <code>Vector</code> object.</p><pre><code>defpackage mypackage :<br> import core<br> import collections<br><br>defn main () :<br> val v = Vector<Int>()<br> add(v, 1)<br> add(v, 2)<br> add(v, 3)<br> println(v)<br><br>main()</code></pre><p>It prints out</p><pre><code>[1 2 3]</code></pre><p>A <code>Vector</code> object is similar to an array and represents a mutable collection of items where each item is associated with an integer index. However, whereas arrays are of fixed length, a vector can grow and shrink to accomodate more or less items. </p><p>The type of the <code>v</code> vector in the example above is </p><pre><code>Vector<Int></code></pre><p>indicating that it is a vector for storing integers.</p><p>Here is how to add additional elements to the end of a vector.</p><pre><code>add(v, 42)</code></pre><p>Here is how to retrieve and remove the element at the end of the vector.</p><pre><code>pop(v)</code></pre><p>Identical to the case of arrays, here is how to retrieve the length of a vector, retrieve a value at a particular index, and assign a value to a particular index.</p><pre><code>length(v) ;Retrieve a vector's length<br>v[0] = 42 ;Assign a value to index 0<br>v[0] ;Retrieve the value at index 0</code></pre><h2 id="anchor34">HashTables</h2><p>Hash tables are another commonly used datastructure in the <code>collections</code> package. A table associates a value object with a particular key object. It can be imagined as a two-column table (hence the name) where the left column is named <span style="font-style:italic;">keys</span> and the right column is named <span style="font-style:italic;">values</span>. Each entry in the table is recorded as a new row. The key object is recorded in the keys column, and its corresponding value object is recorded in the values column.</p><p>Here is how to create a HashTable where strings are used as keys, and integers are used as values.</p><pre><code>val num-pets = HashTable<String,Int>()<br>num-pets["Luca"] = 2<br>num-pets["Patrick"] = 1<br>num-pets["Emmy"] = 3<br>println(num-pets)</code></pre><p>The above prints out</p><pre><code>["Patrick" => 1 "Luca" => 2 "Emmy" => 3]</code></pre><h3 id="anchor210">Creation</h3><p>The function</p><pre><code>HashTable<String,Int>()</code></pre><p>creates a new hash table that associates integer values with string keys. The type of the table created by the above function is</p><pre><code>HashTable<String,Int></code></pre><p>which indicates that it is a hash table whose keys have type <code>String</code> and whose values have type <code>Int</code>.</p><h3 id="anchor211">Set</h3><p>The calls to <code>set</code></p><pre><code>num-pets["Luca"] = 2<br>num-pets["Patrick"] = 1<br>num-pets["Emmy"] = 3</code></pre><p>associates the value 2 with the key "Luca" in the table, the value 1 with "Patrick", and the value 3 with "Emmy". </p><h3 id="anchor212">Get</h3><p>Here's how to retrieve the value associated with a key.</p><pre><code>println("Emmy has %_ pets." % [num-pets["Emmy"]])</code></pre><p>which prints out</p><pre><code>Emmy has 3 pets.</code></pre><h3 id="anchor213">Does a Key Exist?</h3><p>Attempting to retrieve the value in a table corresponding to a key that doesn't exist is a fatal error. Use the <code>key?</code> function to check whether a key exists in the table.</p><pre><code>if key?(num-pets, "George") :<br> println("George has %_ pets." % [num-pets["George"]])<br>else :<br> println("I don't know how many pets George has.")</code></pre><h3 id="anchor214">Default Values</h3><p>A hash table can also be created with a <span style="font-style:italic;">default</span> value. If a hash table has a default value, then this default value is returned when retrieving the corresponding value for a key that does not exist in the table. Change the definition of num-pets to</p><pre><code>val num-pets = HashTable<String,Int>(0)</code></pre><p>Now when we retrieve the number of pets owned by George,</p><pre><code>println("George has %_ pets." % [num-pets["George"]])</code></pre><p>it prints out</p><pre><code>George has 0 pets.</code></pre><h2 id="anchor35">KeyValue Pairs</h2><p>A <code>KeyValue</code> object represents an association between a key object and a value object. It can be created using the <code>KeyValue</code> function.</p><pre><code>val kv = KeyValue(4, "Hello")</code></pre><p>creates a <code>KeyValue</code> object that represents the mapping from the key <code>4</code> to the value <code>"Hello"</code>. This is done very commonly, so Stanza also provides a convenient operator. The above can be written equivalently as</p><pre><code>val kv = 4 => "Hello"</code></pre><p>The type of the <code>kv</code> object created above is</p><pre><code>KeyValue<Int,String></code></pre><p>which indicates that it represents an association between a key of type <code>Int</code> and a value of type <code>String</code>.</p><p>The key and the value objects in a <code>KeyValue</code> object can be retrieved using the <code>key</code> and <code>value</code> functions respectively.</p><pre><code>key(kv) ;Retrieve the key<br>value(kv) ;Retrieve the value</code></pre><h2 id="anchor36">For Loops over Sequences</h2><p>Thus far you've only been shown how to use the for construct for simple counting loops. Here you'll see how the for construct generalizes to all types of collections.</p><p>The for loop can be used to iterate directly through the items of an array like so.</p><pre><code>val xs = Array<Int>(4)<br>xs[0] = 2<br>xs[1] = 42<br>xs[2] = 7<br>xs[3] = 1<br><br>for x in xs do :<br> println(x)</code></pre><p>which prints out</p><pre><code>2<br>42<br>7<br>1</code></pre><h3 id="anchor215">General Form</h3><p>Here is the general form.</p><pre><code>for x in xs do :<br> body</code></pre><p>For each item in the <span style="font-style:italic;">collection</span> <code>xs</code>, the for loop executes <code>body</code> once with <code>x</code> bound to the next item in the collection. In our example, <code>xs</code> contains the numbers <code>2</code>, <code>42</code>, <code>7</code>, and <code>1</code>, and thus <code>body</code> is executed once each with <code>x</code> bound to <code>2</code>, <code>42</code>, <code>7</code>, and finally <code>1</code>. </p><h3 id="anchor216">Examples of Collections</h3><p>We will more precisely specify what constitutes a <span style="font-style:italic;">collection</span> later. For now, just accept that arrays, vectors, and tuples are collections, and strings are collections of characters. For example,</p><pre><code>for c in "Timon" do :<br> print("Next char is ")<br> println(c)</code></pre><p>prints out</p><pre><code>Next char is T<br>Next char is i<br>Next char is m<br>Next char is o<br>Next char is n</code></pre><p>And similarly,</p><pre><code>for x in [1, 3, "Timon"] do :<br> print("Next item is ")<br> println(x)</code></pre><p>prints out</p><pre><code>Next item is 1<br>Next item is 3<br>Next item is Timon</code></pre><p>In fact, <code>Range</code> objects are collections of integers, so the counting loops we saw before are actually just a special case of iterating through the items in a <code>Range</code>. </p><pre><code>val r = 0 to 4<br>for x in r do :<br> print("Next number is ")<br> println(x)</code></pre><p>prints out</p><pre><code>Next number is 0<br>Next number is 1<br>Next number is 2<br>Next number is 3</code></pre><p>Tables are also collections, but they are collections of <code>KeyValue</code> objects, each representing one of the entries in the table. The following</p><pre><code>val num-pets = HashTable<String,Int>()<br>num-pets["Luca"] = 2<br>num-pets["Patrick"] = 1<br>num-pets["Emmy"] = 3<br><br>for entry in num-pets do :<br> println("%_ has %_ pets." % [key(entry), value(entry)])</code></pre><p>prints out</p><pre><code>Patrick has 1 pets.<br>Luca has 2 pets.<br>Emmy has 3 pets.</code></pre><p>As you can see, Stanza's for construct is extremely powerful. In truth, the form shown here is <span style="font-style:italic;">still</span> not the most general form of the for construct. We'll learn about that after we've covered first class functions.</p><h2 id="anchor37">Extended Example: Complex Number Package</h2><p>In this extended example, we will implement a package for creating and performing arithmetic with complex numbers. </p><h3 id="anchor217">The Complex Package</h3><p>Create a file called <code>complex.stanza</code> with the following content.</p><pre><code>defpackage complex :<br> import core<br><br>public defstruct Cplx :<br> real: Double<br> imag: Double</code></pre><p>This struct will be our representation for complex numbers. It is stored in cartesian form and has real and imaginary components. </p><h3 id="anchor218">Printing Complex Numbers</h3><p>To be able to print <code>Cplx</code> objects, we provide a custom print method.</p><pre><code>defmethod print (o:OutputStream, x:Cplx) :<br> if imag(x) >= 0.0 :<br> print(o, "%_ + %_i" % [real(x), imag(x)])<br> else :<br> print(o, "%_ - %_i" % [real(x), (- imag(x))])</code></pre><h3 id="anchor219">Main Driver</h3><p>To test our program thus far, create a file called <code>complexmain.stanza</code> with the following content.</p><pre><code>defpackage complex/main :<br> import core<br> import complex<br><br>defn main () :<br> val a = Cplx(1.0, 5.0)<br> val b = Cplx(3.0, -4.0)<br> println(a)<br> println(b)<br><br>main()</code></pre><p>Compile and run the program by typing the following in the terminal.</p><pre><code>stanza complex.stanza complexmain.stanza -o cplx<br>./cplx</code></pre><p>It should print out</p><pre><code>1.000000000000000 + 5.000000000000000i<br>3.000000000000000 - 4.000000000000000i</code></pre><p>Great! So now we can create and print out complex numbers. If you're an electrical engineer, you may substitute <code>i</code> for <code>j</code> in the <code>print</code> method.</p> <h3 id="anchor220">Arithmetic Operations</h3><p>The next step is to implement the standard arithmetic operations for complex numbers. Pull out your old algebra textbooks and look up the formulas. Or pick up a pencil and derive them yourself. </p><pre><code>public defn plus (a:Cplx, b:Cplx) :<br> Cplx(real(a) + real(b), imag(a) + imag(b))<br><br>public defn minus (a:Cplx, b:Cplx) :<br> Cplx(real(a) - real(b), imag(a) - imag(b))<br><br>public defn times (a:Cplx, b:Cplx) :<br> val x = real(a)<br> val y = imag(a)<br> val u = real(b)<br> val v = imag(b)<br> Cplx(x * u - y * v, x * v + y * u)<br><br>public defn divide (a:Cplx, b:Cplx) :<br> val x = real(a)<br> val y = imag(a)<br> val u = real(b)<br> val v = imag(b)<br> val den = u * u + v * v<br> Cplx((x * u + y * v) / den, (y * u - x * v) / den)</code></pre><p>Let's test out our operators.</p><pre><code>defn main () :<br> val a = Cplx(1.0, 5.0)<br> val b = Cplx(3.0, -4.0)<br> println("(%_) + (%_) = %_" % [a, b, a + b])<br> println("(%_) - (%_) = %_" % [a, b, a - b])<br> println("(%_) * (%_) = %_" % [a, b, a * b])<br> println("(%_) / (%_) = %_" % [a, b, a / b])<br><br>main()</code></pre><p>The program prints out</p><pre><code>(1.000000000000000 + 5.000000000000000i) + (3.000000000000000 - 4.000000000000000i)<br> = 4.000000000000000 + 1.000000000000000i<br>(1.000000000000000 + 5.000000000000000i) - (3.000000000000000 - 4.000000000000000i)<br> = -2.000000000000000 + 9.000000000000000i<br>(1.000000000000000 + 5.000000000000000i) * (3.000000000000000 - 4.000000000000000i)<br> = 23.000000000000000 + 11.000000000000000i<br>(1.000000000000000 + 5.000000000000000i) / (3.000000000000000 - 4.000000000000000i)<br> = -0.680000000000000 + 0.760000000000000i</code></pre><p>which looks right to me!</p><h3 id="anchor221">Root Finding</h3><p>Armed with our new complex number package, let's now put it to good use and solve an equation. We will use the Newton-Raphson method to solve the following equation.</p><pre><code>x ^ 3 - 1 = 0</code></pre><p>Here is our numerical solver which takes an initial guess, <code>x0</code>, and the number of iterations, <code>num-iter</code>, and performs <code>num-iter</code> number of Newton-Raphson iterations to find the root of the equation.</p><pre><code>defn newton-raphson (x0:Cplx, num-iter:Int) :<br> var xn = x0<br> for i in 0 to num-iter do :<br> xn = xn - (xn * xn * xn - Cplx(1.0,0.0)) / (Cplx(3.0,0.0) * xn * xn)<br> xn </code></pre><p>Let's test it!</p><pre><code>defn main () :<br> println(newton-raphson(Cplx(1.0,1.0), 100))</code></pre><p>The program prints out</p><pre><code>1.000000000000000 + 0.000000000000000i</code></pre><p>which is indeed one of the solutions to the equation! Fantastic!</p><h3 id="anchor222">Find all the Roots!</h3><p>But according to the Fundamental Theorem of Algebra, the equation should have two more solutions. Different initial guesses will converge to different solutions so let's try a whole bunch of different guesses and try to find them all.</p><p>Here is a function that takes in a tuple of initial guesses and tries them all.</p><pre><code>defn guess (xs:Tuple<Cplx>) :<br> for x in xs do :<br> val r = newton-raphson(x, 100)<br> println("Initial guess %_ gave us solution %_." % [x, r])</code></pre><p>And let's call it with a bunch of random guesses.</p><pre><code>defn main () :<br> guess([Cplx(1.0,1.0), Cplx(2.0,2.0), Cplx(-1.0,3.0), Cplx(-1.0,-1.0)])</code></pre><p>The program prints out</p><pre><code>Initial guess 1.000000000000000 + 1.000000000000000i gave <br> us solution 1.000000000000000 + 0.000000000000000i.<br>Initial guess 2.000000000000000 + 2.000000000000000i gave <br> us solution 1.000000000000000 + 0.000000000000000i.<br>Initial guess -1.000000000000000 + 3.000000000000000i gave <br> us solution -0.500000000000000 + 0.866025403784439i.<br>Initial guess -1.000000000000000 - 1.000000000000000i gave <br> us solution -0.500000000000000 - 0.866025403784439i.</code></pre><p>Thus the three solutions to the equation are <code>1</code>, <code>-0.5 + 0.866i</code>, and <code>-0.5 - 0.866i</code>. Problem solved!</p>
</td>
<td class="rest">
<img url="resources/spacer.gif"></img>
</td>
</tr>
<tr><td colspan="3" class="footer">
Site design by Luca Li. Copyright 2015.
</td></tr>
</table>
</body>
</html>