That wasn't so bad, now was it? Now, let's take a look at my solution: ```coconut def diagonal_line(n) = range(n+1) |> map\$((i) -> (i, n-i)) ``` Pretty simple, huh? We take `range(n+1)`, and use `map` to transform it into the right sequence of tuples. ### `linearized_plane` Now that we've created our diagonal lines, we need to join them together to make the full linearized plane, and to do that we're going to write the function `linearized_plane()`. `linearized_plane` should produce an iterator that goes through all the points in the plane, in order of all the points in the first `diagonal(0)`, then the second `diagonal(1)`, and so on. `linearized_plane` is going to be, by necessity, an infinite iterator, since it needs to loop through all the points in the plane, which have no end. To help you accomplish this, remember that the `::` operator is lazy, and won't evaluate its operands until they're needed, which means it can be used to construct infinite iterators. When you're ready to move on, scroll down. Tests: ```coconut # Note: these tests use \$[] notation, which we haven't introduced yet # but will introduce later in this case study; for now, just run the # tests, and make sure you get the same result as is in the comment linearized_plane()\$[0] |> print # (0, 0) linearized_plane()\$[:3] |> list |> print # [(0, 0), (0, 1), (1, 0)] ``` _Hint: instead of defining the function as `linearized_plane()`, try defining it as `linearized_plane(n=0)`, where `n` is the diagonal to start at, and use recursion to build up from there._

That was a little bit rougher than the first one, but hopefully still not too bad. Let's compare to my solution: ```coconut def linearized_plane(n=0) = diagonal_line(n) :: linearized_plane(n+1) ``` As you can see, it's a very fundamentally simple solution: just use `::` and recursion to join all the diagonals together in order. ### `vector_field` Now that we have a function that builds up all the points we need, it's time to turn them into vectors, and to do that we'll define the new function `vector_field()`, which should turn all the tuples in `linearized_plane` into vectors, using the n-vector class we defined earlier. Tests: ```coconut # You'll need to bring in the vector class from earlier to make these work vector_field()\$[0] |> print # vector(pts=(0, 0)) vector_field()\$[2:3] |> list |> print # [vector(pts=(1, 0))] ``` _Hint: Remember, the way we defined vector it takes the components as separate arguments, not a single tuple._

Here's my solution for you to check against: ```coconut def __truediv__(self, other) = self.pts |> map\$((x) -> x/other) |*> vector ``` ### `.unit` Next up, `.unit`. We're going to write a `unit` method that takes just `self` as its argument and returns a new vector the same size as `self` with each element divided by the magnitude of `self`, which we can retrieve with `abs`. This should be a very simple one-line function. Tests: ```coconut vector(0, 1).unit() |> print # vector(pts=(0.0, 1.0)) vector(5, 0).unit() |> print # vector(pts=(1.0, 0.0)) ```

Here's my solution: ```coconut def unit(self) = self / abs(self) ``` ### `.angle` This one is going to be a little bit more complicated. For starters, the mathematical formula for the angle between two vectors is the `math.acos` of the dot product of those vectors' respective unit vectors, and recall that we already implemented the dot product of two vectors when we wrote `__mul__`. So, `.angle` should take `self` as the first argument and `other` as the second argument, and if `other` is a vector, use that formula to compute the angle between `self` and `other`, or if `other` is not a vector, `.angle` should raise a `MatchError`. To accomplish this, we're going to want to use destructuring assignment to check that `other` is indeed a `vector`. Tests: ```coconut import math vector(2, 0).angle(vector(3, 0)) |> print # 0.0 print(vector(1, 0).angle(vector(0, 2)), math.pi/2) # should be the same vector(1, 2).angle(5) # MatchError ``` _Hint: Look back at how we checked whether the argument to `factorial` was an integer using destructuring assignment._

Here's my solution—take a look: ```coconut def angle(self, other is vector) = math.acos(self.unit() * other.unit()) ``` And now it's time to put it all together. Feel free to substitute in your own versions of the methods we just defined. ```coconut import math # necessary for math.acos in .angle data vector(pts): """Immutable n-vector.""" def __new__(cls, *pts): """Create a new vector from the given pts.""" if len(pts) == 1 and pts[0] `isinstance` vector: return pts[0] # vector(v) where v is a vector should return v else: return pts |> tuple |> datamaker(cls) # accesses base constructor def __abs__(self) = """Return the magnitude of the vector.""" self.pts |> map\$(pow\$(?, 2)) |> sum |> pow\$(?, 0.5) def __add__(self, other) = """Add two vectors together.""" vector(other_pts) = other assert len(other_pts) == len(self.pts) map((+), self.pts, other_pts) |*> vector def __sub__(self, other) = """Subtract one vector from another.""" vector(other_pts) = other assert len(other_pts) == len(self.pts) map((-), self.pts, other_pts) |*> vector def __neg__(self) = """Retrieve the negative of the vector.""" self.pts |> map\$((-)) |*> vector def __eq__(self, other): """Compare whether two vectors are equal.""" match vector(=self.pts) in other: return True else: return False def __mul__(self, other): """Scalar multiplication and dot product.""" match vector(other_pts) in other: assert len(other_pts) == len(self.pts) return map((*), self.pts, other_pts) |> sum # dot product else: return self.pts |> map\$((*)\$(other)) |*> vector # scalar multiplication def __rmul__(self, other) = """Necessary to make scalar multiplication commutative.""" self * other # New one-line functions necessary for finding the angle between vectors: def __truediv__(self, other) = self.pts |> map\$((x) -> x/other) |*> vector def unit(self) = self / abs(self) def angle(self, other is vector) = math.acos(self.unit() * other.unit()) # Test cases: vector(3, 4) / 1 |> print # vector(pts=(3.0, 4.0)) vector(2, 4) / 2 |> print # vector(pts=(1.0, 2.0)) vector(0, 1).unit() |> print # vector(pts=(0.0, 1.0)) vector(5, 0).unit() |> print # vector(pts=(1.0, 0.0)) vector(2, 0).angle(vector(3, 0)) |> print # 0.0 print(vector(1, 0).angle(vector(0, 2)), math.pi/2) # should be the same vector(1, 2).angle(5) # MatchError ``` _One note of warning here: be careful not to leave a blank line when substituting in your methods, or the interpreter will cut off the code for the `vector` there. This isn't a problem in normal Coconut code, only here because we're copy-and-pasting into the command line._ Copy, paste! If everything is working, I'd recommend going back to playing around with `vector_field` [applications](#applications) using our new methods. ## Filling in the Gaps And with that, this tutorial is out of case studies—but that doesn't mean Coconut is out of features! In this last section, we'll touch on three of the most important features of Coconut that we managed to miss in our case studies: lazy lists, function composition, and implicit partials. ### Lazy Lists First up is lazy lists. Lazy lists are lazily-evaluated iterator literals, similar in their laziness to Coconut's `::` operator, in that any expressions put inside a lazy list won't be evaluated until that element of the lazy list is needed. The syntax for lazy lists is exactly the same as the syntax for normal lists, but with "banana brackets" (`(|` and `|)`) instead of normal brackets, like so: ```coconut abc = (| a, b, c |) ``` ### Function Composition Next is function composition. In Coconut, this is accomplished through the `..` operator, which takes two functions and composes them, creating a new function equivalent to `(*args, **kwargs) -> f1(f2(*args, **kwargs))`. This can be useful in combination with partial application for piecing together multiple higher-order functions, like so: ```coconut zipsum = map\$(sum)..zip ``` Function composition also gets rid of the need for lots of parentheses when chaining function calls, like so: ```coconut (plus1..square)(3) == 10 ``` ### Implicit Partials Last is implicit partials. Coconut supports a number of different "incomplete" expressions that will evaluate to a function that takes in the part necessary to complete them, that is, an implicit partial application function. The different allowable expressions are: ```coconut .attr .method(args) obj. func\$ seq[] iter\$[] .[slice] .\$[slice] ``` ### Further Reading And that's it for this tutorial! But that's hardly it for Coconut. All of the features examined in this tutorial, as well as a bunch of others, are documented in detail in Coconut's comprehensive [documentation](http://coconut.readthedocs.io/en/master/DOCS.html). Also, if you have any other questions not covered in this tutorial, feel free to ask around at Coconut's [Gitter](https://gitter.im/evhub/coconut), a GitHub-integrated chat room for Coconut developers. Finally, Coconut is a new, growing language, and if you'd like to get involved in the development of Coconut, all the code is available completely open-source on Coconut's [GitHub](https://github.com/evhub/coconut). Contributing is a simple as forking the code, making your changes, and proposing a pull request.