f
This commit is contained in:
commit
399845160c
319 changed files with 125222 additions and 0 deletions
2
public-class-repo/.gitignore
vendored
Normal file
2
public-class-repo/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Emacs temp files
|
||||
*~
|
319
public-class-repo/Homework/Hwk_01.md
Normal file
319
public-class-repo/Homework/Hwk_01.md
Normal file
|
@ -0,0 +1,319 @@
|
|||
# Homework 1: OCaml introduction: functions, lists, tuples
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
**Due:** Monday, January 30 at 5:00pm
|
||||
|
||||
## Introduction
|
||||
|
||||
Below, you are asked to write a number of OCaml functions. Some are
|
||||
simple, such as a function to determine if an integer input is even or
|
||||
not. Others are more interesting and ask you to compute the square
|
||||
root of a floating point number to a specified degree of accuracy.
|
||||
|
||||
Designing and implementing these functions will give you the
|
||||
opportunity to test your knowledge of OCaml and how to write recursive
|
||||
functions in it. Successfully completing these will set you up for
|
||||
the more advanced (and more interesting) topics covered in this
|
||||
course.
|
||||
|
||||
Recall that while some labs may be done collaboratively, *this work
|
||||
is meant to be done on your own.*
|
||||
|
||||
## Designing and implementing functions in OCaml
|
||||
|
||||
All functions should be placed in a file named ``hwk_01.ml`` which
|
||||
resides in a directory named ``Hwk_01``. This directory should be in
|
||||
your GitHub repository.
|
||||
|
||||
In implementing these functions, do not use any functions from the
|
||||
``List`` module. If you need some helper functions over lists, write
|
||||
them yourself.
|
||||
|
||||
Also, you should only use the pure, non-imperative features of OCaml.
|
||||
No while-loops or references. But since we've not discussed these
|
||||
they are easy to avoid.
|
||||
|
||||
|
||||
|
||||
### even or odd
|
||||
|
||||
Write an OCaml function named ``even`` with the type ``int -> bool``
|
||||
that returns ``true`` if its input is even, ``false`` otherwise.
|
||||
|
||||
Recall that we used the OCaml infix operator ``mod`` in class. You
|
||||
may find it useful here.
|
||||
|
||||
Some example evaluations:
|
||||
+ ``even 4`` evaluates to ``true``
|
||||
+ ``even 5`` evaluates to ``false``
|
||||
|
||||
|
||||
|
||||
### Another GCD, Euclid's algorithmm
|
||||
|
||||
In class we wrote a greatest common divisor function that computed the
|
||||
GCD of two positive integers by counting down by 1 from an initial
|
||||
value that was greater than or equal to the GCD until we reached a
|
||||
common divisor.
|
||||
|
||||
You are now asked to write another GCD function that is both simpler
|
||||
to write and faster.
|
||||
|
||||
This one is based on the following observations:
|
||||
+ gcd(a,b) = a, if a = b
|
||||
+ gcd(a,b) = gcd(a, b-a), if a<b
|
||||
+ gcd(a,b) = gcd(a-b,b) if a>b
|
||||
|
||||
This function should be named ``euclid`` and have the type ``int ->
|
||||
int -> int``.
|
||||
|
||||
To get full credit on this problem, your solution must be based on the
|
||||
observations listed above.
|
||||
|
||||
Some example evaluations:
|
||||
+ ``euclid 6 9`` evaluates to ``3``
|
||||
+ ``euclid 5 9`` evaluates to ``1``
|
||||
|
||||
|
||||
|
||||
### Adding and multiplying fractions
|
||||
|
||||
We can use OCaml's tuples to represent fractions as a pair of
|
||||
integers. For example, the value ``(1,2)`` of type ``int * int``
|
||||
represents the value one-half; ``(5,8)`` represents the value
|
||||
five-eighths.
|
||||
|
||||
Consider the following function for multiplying two fractions
|
||||
```
|
||||
let frac_mul (n1,d1) (n2,d2) = (n1 *n2, d1 * d2)
|
||||
```
|
||||
It has type ``int * int -> int * int -> int * int``.
|
||||
|
||||
The expression ``frac_mul (1,2) (1,3)`` evaluates to ``(1,6)``.
|
||||
|
||||
Now write a function named ``frac_add`` that adds two fractions. It
|
||||
should have the same type as our addition function: ``(int * int) ->
|
||||
(int * int) -> (int * int)``.
|
||||
|
||||
You may assume that the denominator of any fraction is never 0.
|
||||
|
||||
Some example evaluations:
|
||||
+ ``frac_add (1,2) (1,3)`` evaluates to ``(5,6)``
|
||||
+ ``frac_add (1,4) (1,4)`` evaluates to ``(8,16)``
|
||||
|
||||
We see here that your addition function need not simplify fractions,
|
||||
that is the job of the next function.
|
||||
|
||||
|
||||
|
||||
### Simplifiying fractions
|
||||
|
||||
Write another fraction function that simplifies fractions. It should
|
||||
be called
|
||||
``frac_simplify`` with type ``(int * int) -> (int * int)``.
|
||||
|
||||
Consider the following sample evaluations:
|
||||
+ ``frac_simplify (8,16)`` evaluates to ``(1,2)``
|
||||
+ ``frac_simplify (4,9)`` evaluates to ``(4,9)``
|
||||
+ ``frac_simplify (3,9)`` evaluates to ``(1,3)``
|
||||
|
||||
As before, you may assume that the denominator is never 0.
|
||||
|
||||
You may want to use your ``euclid`` function in writing ``frac_simplify``.
|
||||
|
||||
|
||||
|
||||
### Square root approximation
|
||||
|
||||
Consider the following algorithms written in psuedo-code similar to C.
|
||||
Assume that the "input" value ``n`` is greater than 1.0 and all
|
||||
variables hold real numbers.
|
||||
```
|
||||
lower = 1.0;
|
||||
upper = n;
|
||||
accuracy = 0.001;
|
||||
while ( (upper-lower) > accuracy ) {
|
||||
guess = (lower + upper) / 2.0;
|
||||
if ( (guess*guess) > n)
|
||||
upper = guess;
|
||||
else
|
||||
lower = guess;
|
||||
}
|
||||
```
|
||||
After this algorithm terminates we know that
|
||||
*upper >= sqrt(n) >= lower* and
|
||||
*upper - lower <= accuracy*.
|
||||
That is, lower and upper proivde a bound on the actual square root of
|
||||
n and that this bound is within the specified accuracy.
|
||||
|
||||
You are asked to write a function named ``square_approx`` with type
|
||||
``float -> float -> (float * float)`` that implements the above
|
||||
imperative algorithm, returning a pair of values corresponding to
|
||||
``lower`` and ``upper`` in the imperative psuedo-code.
|
||||
|
||||
The first argument corresponds to ``n``, the value of which
|
||||
we want to take the square root, and the second corresponds
|
||||
to ``accuracy``.
|
||||
|
||||
Of course, this should be a recursive function that does not use any
|
||||
of OCaml's imperative features such as while-loops and references.
|
||||
|
||||
Consider the gcd function that we wrote in class since it has some
|
||||
characteristics that are similar to those needed for this function -
|
||||
namely the need to carry additional changing values along the chain of
|
||||
recursive function calls as additional parameters.
|
||||
|
||||
Consider the following sample evaluations:
|
||||
+ ``square_approx 9.0 0.001`` evaluates to ``(3.,3.0009765625)``
|
||||
+ ``square_approx 81.0 0.1`` evaluates to ``(8.96875,9.046875)``
|
||||
|
||||
(Small round off errors of floating point values are acceptable of
|
||||
course.)
|
||||
|
||||
|
||||
|
||||
### Maximum in a list
|
||||
|
||||
Write a function ``max_list`` that takes a list of integers as input
|
||||
and returns the maximum.
|
||||
This function should have the type ``int list -> int``.
|
||||
|
||||
In your solution, write a comment that specifies any restrictions on
|
||||
the lists that can be passed as input to your function.
|
||||
|
||||
Some sample interactions:
|
||||
+ ``max_list [1; 2; 5; 3; 2]`` evaluates to ``5``
|
||||
+ ``max_list [-1; -2; -5; -3; -2]`` evaluates to ``-1``
|
||||
|
||||
|
||||
|
||||
### Dropping list elements
|
||||
|
||||
Write another list processing function called ``drop`` with type ``int -> 'a list -> 'a list`` that drops a specified number of elements
|
||||
from the input list.
|
||||
|
||||
For example, consider these evaluations:
|
||||
+ ``drop 3 [1; 2; 3; 4; 5]`` evaluates to ``[4; 5]``
|
||||
+ ``drop 5 ["A"; "B"; "C"]`` evaluates to ``[ ]``
|
||||
+ ``drop 0 [1]`` evaluates to ``[1]``
|
||||
|
||||
You may assume that only non-negative numbers will be passed as the
|
||||
first argument to ``drop``.
|
||||
|
||||
|
||||
|
||||
### List reverse
|
||||
|
||||
Write a function named ``rev`` that takes a list and returns the
|
||||
reverse of that list.
|
||||
|
||||
Recall that ``@`` is the list append operator, you may find this useful.
|
||||
|
||||
Some sample interactions:
|
||||
+ ``rev [1; 2; 3; 4; 5]`` evaluates to ``[5; 4; 3; 2; 1]``
|
||||
+ ``rev []`` evaluates to ``[]``
|
||||
|
||||
|
||||
|
||||
### Closed polygon perimeter
|
||||
|
||||
This final problem asks you to compute the perimeter of a closed polygon
|
||||
represented by a list of points.
|
||||
|
||||
You may assume that the list contains at least 3 elements (though our
|
||||
solution only requires that the list be non-empty). You may also
|
||||
assume that drawing line segments between each successive pair of
|
||||
points leads to a closed polygon with no crossing lines.
|
||||
|
||||
Your function should be named ``perimeter`` and have the type
|
||||
``(float * float) list -> float``.
|
||||
|
||||
|
||||
This function is similar to ``sum_diffs`` from Lab 02 in that we apply
|
||||
some function to each successive pair of points. In this case that
|
||||
function is ``distance`` (also from Lab 02) instead of integer
|
||||
subtraction.
|
||||
|
||||
But we must also include the distance between the first point in the
|
||||
list and the last point in the list. So when our recursive function
|
||||
gets to the base case of having just one more point in the list, it
|
||||
must have access to the first point in the list so that we can return
|
||||
the distance between the first and last points.
|
||||
|
||||
You will likely need to write a helper function, in a let-expression
|
||||
nested in your definition of ``perimeter`` that carries along the
|
||||
value of the first point until it is needed.
|
||||
|
||||
Recall how, in our GCD function, we carried along the value of the
|
||||
potential GCD value that was decremented in each recursive call. You
|
||||
will need to do something similar here; the only difference being that
|
||||
the "carried along" value doesn't change with each call to the
|
||||
recursive function.
|
||||
|
||||
|
||||
A sample interaction:
|
||||
+ ``perimeter [ (1.0, 1.0); (1.0, 3.0); (4.0, 4.0); (7.0, 3.0); (7.0, 1.0) ]``
|
||||
evalutes to, roughly ``16.32``
|
||||
|
||||
|
||||
|
||||
### Representing matrices as lists of lists
|
||||
|
||||
We could consider representing matrices as lists of lists of numbers.
|
||||
For example the list ``[ [1; 2; 3] ; [4; 5; 6] ]`` might represent a
|
||||
matrix with two rows (each row corresponding to one of the "inner"
|
||||
lists) and three columns.
|
||||
|
||||
Here the type is ``int list list`` - a list of integer lists.
|
||||
|
||||
Of course, the type allows for values that do not correspond to
|
||||
matrices. For example, ``[ [1; 2; 3] ; [4; 5] ]`` would not represent
|
||||
a matrix since the first "row" has 3 elements and the second has only
|
||||
2.
|
||||
|
||||
Write a function ``is_matrix`` that takes in values such as the list
|
||||
of lists given above and returns a boolean value of ``true`` if the
|
||||
list of lists represents a proper matrix and ``false`` otherwise.
|
||||
|
||||
This function checks that all the "inner" lists have the same length.
|
||||
Since you are not to use any library functions you need to write your
|
||||
own function to determine the length of a list.
|
||||
|
||||
Some sample interactions:
|
||||
+ ``is_matrix [ [1;2;3]; [4;5;6] ]`` evaluates to ``true``
|
||||
+ ``is_matrix [ [1;2;3]; [4;6] ]`` evaluates to ``false``
|
||||
+ ``is_matrix [ [1] ]`` evaluates to ``true``
|
||||
|
||||
|
||||
|
||||
### A simple matrix operation: matrix scalar addition
|
||||
|
||||
Write a function, ``matrix_scalar_add`` with type ``int list list ->
|
||||
int -> int list list`` that implements matrix scalar addition. This
|
||||
is simply the operation of adding the integer value to each element of
|
||||
the matrix.
|
||||
|
||||
For example,
|
||||
+ ``matrix_scalar_add [ [1; 2 ;3]; [4; 5; 6] ] 5`` evaluates to
|
||||
``[ [6; 7; 8]; [9; 10; 11] ]``
|
||||
|
||||
You may assume that only matrices for which ``is_matrix`` evaluates to
|
||||
``true`` are passed to this function.
|
||||
|
||||
|
||||
|
||||
## Bonus round
|
||||
|
||||
For a small number of extra credit points implement a matrix transpose
|
||||
function named ``matrix_transpose`` that has type ``'a list list -> 'a
|
||||
list list``. It should transpose a matrix such as ``[ [1; 2; 3]; [4;
|
||||
5; 6] ]`` into ``[ [1; 4]; [2; 5]; [3; 6] ]``.
|
||||
|
||||
If you're feeling ambitious, try a matrix multiply function as well.
|
||||
To simplify this, we'll assume that matrices hold integers and thus
|
||||
your ``matrix_multiply`` function should have type ``int list list ->
|
||||
int list list -> int list list``.
|
||||
|
||||
|
||||
|
390
public-class-repo/Homework/Hwk_02.md
Normal file
390
public-class-repo/Homework/Hwk_02.md
Normal file
|
@ -0,0 +1,390 @@
|
|||
# Homework 2: Working with higher order functions.
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
**Due:** Friday, February 17 at 5:00pm
|
||||
|
||||
Lab 4 on February 7 and Lab 5 on February 14 will be dedicated to
|
||||
answering questions about this assignment and to providing
|
||||
clarifications if any are needed.
|
||||
|
||||
Note that for this assignment you are not to write **any**
|
||||
recursive functions. Further information on this restriction is
|
||||
detailed in Part 3 of the assignment.
|
||||
|
||||
## Corrections to mistakes in original specification
|
||||
+ The type of ``convert_to_non_blank_lines_of_words`` shoud be ``char list -> line list`` not ``string -> line list``.
|
||||
|
||||
## Introduction - The Paradelle
|
||||
|
||||
In this homework assignment you will write an OCaml program that
|
||||
reads a text file and reports if it contains a poem that fits the
|
||||
"fixed-form" style known as a *paradelle*.
|
||||
|
||||
Below is a sample paradelle called "Paradelle for Susan" by Billy
|
||||
Collins from his book *Picnic, Lightning*.
|
||||
|
||||
|
||||
> I remember the quick, nervous bird of your love. <br/>
|
||||
> I remember the quick, nervous bird of your love. <br/>
|
||||
> Always perched on the thinnest, highest branch. <br/>
|
||||
> Always perched on the thinnest, highest branch. <br/>
|
||||
> Thinnest of love, remember the quick branch. <br/>
|
||||
> Always nervous, I perched on your highest bird the.
|
||||
>
|
||||
> It is time for me to cross the mountain. <br/>
|
||||
> It is time for me to cross the mountain. <br/>
|
||||
> And find another shore to darken with my pain. <br/>
|
||||
> And find another shore to darken with my pain. <br/>
|
||||
> Another pain for me to darken the mountain. <br/>
|
||||
> And find the time, cross my shore, to with it is to.
|
||||
>
|
||||
> The weather warm, the handwriting familiar. <br/>
|
||||
> The weather warm, the handwriting familiar. <br/>
|
||||
> Your letter flies from my hand into the waters below. <br/>
|
||||
> Your letter flies from my hand into the waters below. <br/>
|
||||
> The familiar waters below my warm hand. <br/>
|
||||
> Into handwriting your weather flies your letter the from the.
|
||||
>
|
||||
> I always cross the highest letter, the thinnest bird. <br/>
|
||||
> Below the waters of my warm familiar pain, <br/>
|
||||
> Another hand to remember your handwriting. <br/>
|
||||
> The weather perched for me on the shore. <br/>
|
||||
> Quick, your nervous branch flies for love. <br/>
|
||||
> Darken the mountain, time and find my into it with from to to is.
|
||||
|
||||
|
||||
Following this poem, Collins provides the following description of this form:
|
||||
|
||||
> The paradelle is one of the more demanding French fixed forms, first
|
||||
appearing in the *langue d'oc* love poetry of the eleventh century. It
|
||||
is a poem of four six-line stanzas in which the first and second lines,
|
||||
as well as the third and fourth lines of the first three stanzas, must
|
||||
be identical. The fifth and sixth lines, which traditionally resolve
|
||||
these stanzas, must use *all* the words from the preceding
|
||||
lines and *only* those words. Similarly, the final stanza must
|
||||
use *every* word from *all* the preceding stanzas and
|
||||
*only* those words.
|
||||
|
||||
Collins is actually being satirical here and poking fun at overly
|
||||
rigid fixed-form styles of poetry. There is actually no form known as
|
||||
the *paradelle*. This did not stop people from going off and trying
|
||||
to write their own however. In fact, the above poem is slightly
|
||||
modified from his original so that it actually conforms to the rules
|
||||
of a paradelle.
|
||||
|
||||
|
||||
To write an OCaml program to detect if a text file contains a paradelle
|
||||
we add some more specific requirements to Collin's description above.
|
||||
You should take these into consideration when completing this
|
||||
assignment:
|
||||
|
||||
+ Blank lines are allowed, but we will assume that blank lines
|
||||
consist of only a single newline ``'\n'`` character.
|
||||
|
||||
+ Punctuation and spacing (tabs and the space characters) should
|
||||
not affect the comparison of lines in a stanza. For example, the
|
||||
following two lines would be considered as "identical" because the
|
||||
same words are used in the same order even though spacing and
|
||||
punctuation are different.
|
||||
|
||||
``"And find the time,cross my shore, to with it is to"``
|
||||
|
||||
``"And find the time , cross my shore, to with it is to ."``
|
||||
|
||||
Thus, we will want to ignore punctuation symbols to some extent,
|
||||
being careful to notice that they can separate words as in ``"time,cross"``.
|
||||
|
||||
Specifically, the punctuation we will
|
||||
consider are the following :
|
||||
|
||||
``. ! ? , ; : -``
|
||||
|
||||
Other punctuation symbols will not be used in any input to assess
|
||||
your program.
|
||||
|
||||
+ Also, we will need to split lines in the file (of Ocaml type
|
||||
``string``) into a list of lines
|
||||
and then split each line individual line into a list of
|
||||
words. In the list of words there
|
||||
should be no spaces, tabs, or punctuation symbols. Then we can
|
||||
compare lists of words.
|
||||
|
||||
+ Capitalization does not matter. The words ``"Thinnest"``
|
||||
and "``thinnest"`` are to be considered as the same.
|
||||
|
||||
|
||||
+ In checking criteria for an individual stanza, each instance of
|
||||
a word is counted. But in checking that the final stanza uses all
|
||||
the words of the first 3, duplicate words should be removed.
|
||||
|
||||
That is, in checking that two lines "use the same words" we must
|
||||
check that each word is used the same number of times in each line.
|
||||
|
||||
In checking that the final stanza uses all (and only) words from the
|
||||
first 3 stanza, we do not care about how many times a word is
|
||||
used. So if a word is used 4 times in the first 3 stanzas, it need
|
||||
not be used 4 times in the final stanza.
|
||||
|
||||
|
||||
+ Your program must return a correct answer for any text file.
|
||||
For example, your program should report that an empty file or a file
|
||||
containing a single character or the source code for this assignment
|
||||
are not in the form of a paradelle.
|
||||
|
||||
|
||||
|
||||
## Getting started
|
||||
|
||||
Copy the contexts of the ``Homework/Hwk_02`` directory from the public
|
||||
class repository into a ``Hwk_02`` directory in your individual
|
||||
repository.
|
||||
|
||||
This file ``hwk_02.ml`` contains some helper functions that we'll use
|
||||
in this assignment. The remainder are sample files containing
|
||||
paradelles or text that is not a paradelle. The file names should
|
||||
make this all clear.
|
||||
|
||||
|
||||
|
||||
## Part 1. Some useful functions.
|
||||
|
||||
Your first step is to define these functions that will be useful in
|
||||
solving the paradelle check. Place this near the top of the
|
||||
``hwk_02.ml`` file, just after the comment that says
|
||||
```
|
||||
(* Place part 1 functions 'take', 'drop', 'length', 'rev',
|
||||
'is_elem_by', 'is_elem', 'dedup', and 'split_by' here. *)
|
||||
```
|
||||
|
||||
### a length function, ``length``
|
||||
|
||||
Write a function, named ``length`` that, as you would expect, takes a
|
||||
list and returns its length as a value of type ``int``
|
||||
|
||||
Annotate your function with types or add a comment
|
||||
indicating the type of the function.
|
||||
|
||||
|
||||
### list reverse ``rev``
|
||||
|
||||
Complete the definition of the reverse function ``rev`` in
|
||||
``hwk_02.ml``. Currently is just raises an exception. Remove this
|
||||
and replace the body with an expression that uses List.fold_left
|
||||
or List.fold_right to do the work of reversing the list.
|
||||
|
||||
### list membership ``is_elem_by`` and ``is_elem``
|
||||
|
||||
Define a function ``is_elem_by`` which has the type
|
||||
```
|
||||
('a -> 'b -> bool) -> 'b -> 'a list -> bool
|
||||
```
|
||||
The first argument is a function to check if an element in the list
|
||||
(the third argument) matches the values of the second argument. It
|
||||
will return ``true`` if any element in the list "matches" (based on
|
||||
what the first argument determines) an element in the list.
|
||||
|
||||
For example, both
|
||||
```
|
||||
is_elem_by (=) 4 [1; 2; 3; 4; 5; 6; 7]
|
||||
```
|
||||
and
|
||||
```is_elem_by (fun c i -> Char.code c = i) 99 ['a'; 'b'; 'c'; 'd']``
|
||||
evaluate to true.
|
||||
|
||||
Next, define a function ``is_elem`` whose first argument is a value and second
|
||||
argument is a list of values of the same type. The function returns
|
||||
``true`` if the value is in the list.
|
||||
|
||||
For example, ``is_elem 4 [1; 2; 3; 4; 5; 6; 7]`` should evaluate to
|
||||
``true`` while ``is_elem 4 [1; 2; 3; 5; 6; 7]`` and ``is_elem 4 [ ]``
|
||||
should both evaluate to ``false``.
|
||||
|
||||
``is_elem`` should be be implemented by calling ``is_elem_by``.
|
||||
|
||||
Annotate both of your functions with type information on the arguments
|
||||
and for the result type.
|
||||
|
||||
|
||||
### removing duplicates from a list, ``dedup``
|
||||
|
||||
Write a function named ``dedup`` that takes a list and removes all
|
||||
duplicates from the list. The order of list elements returned is up
|
||||
to you. This can be done with only a call to ``List.fold_right``,
|
||||
providing you pass it the correct function that can be used to fold a
|
||||
list up into one without any duplicate elements.
|
||||
|
||||
|
||||
### a splitting function, ``split_by``
|
||||
|
||||
Write a splitting function named ``split_by`` that takes three arguments
|
||||
|
||||
1. an equality checking function that takes two values
|
||||
and returns a value of type ``bool``,
|
||||
|
||||
2. a list of values that are to be separated,
|
||||
|
||||
3. and a list of separators values.
|
||||
|
||||
|
||||
This function will split the second list into a list of lists. If the
|
||||
checking function indicates that an element of the first list
|
||||
(the second argument) is an element of the second list (the third
|
||||
argument) then that element indicates that the list should be split at
|
||||
that point. Note that this "splitting element" does not appear
|
||||
in any list in the output list of lists.
|
||||
|
||||
For example,
|
||||
+ ``split_by (=) [1;2;3;4;5;6;7;8;9;10;11] [3;7]`` should evaluate to
|
||||
``[ [1;2]; [4;5;6]; [8;9;10;11] ]`` and
|
||||
+ ``split_by (=) [1;2;3;3;3;4;5;6;7;7;7;8;9;10;11] [3;7]`` should
|
||||
evaluate to ``[[1; 2]; []; []; [4; 5; 6]; []; []; [8; 9; 10; 11]]``.
|
||||
|
||||
Note the empty lists. These are the list that occur between the 3's
|
||||
and 7's.
|
||||
|
||||
+ ``split_by (=) ["A"; "B"; "C"; "D"] ["E"]`` should evaluate to
|
||||
``[["A"; "B"; "C"; "D"]]``
|
||||
|
||||
Annotate your function with types.
|
||||
|
||||
Also add a comment explaining the behavior of your function and its
|
||||
type. Try to write this function so that the type is as general as
|
||||
possible.
|
||||
|
||||
|
||||
## Reading file contents.
|
||||
|
||||
Notice the provide helper functions ``read_chars`` and ``read_file``.
|
||||
The second will read a file and return the list of characters, wrapped
|
||||
up in an ``option`` type if it finds the file. If the file, with the
|
||||
name passed to the function, can't be found, it will return ``None``.
|
||||
|
||||
|
||||
|
||||
## Part 2. Preparing text for the paradelle check.
|
||||
|
||||
The poems that we aim to check are stored as values of type ``string``
|
||||
in text files. But the ``read_file`` function above will return this
|
||||
data in a value of type ``char list option``.
|
||||
|
||||
We will need to break the input into a list of lines of text, removing
|
||||
the blank lines, and also splitting the lines of text into lists of
|
||||
words.
|
||||
|
||||
We need to write a function called
|
||||
``convert_to_non_blank_lines_of_words`` that takes as input the poem
|
||||
as an OCaml ``char list`` and returns a list of lines, where each line is
|
||||
a list of words, and each word is a list of characters.
|
||||
|
||||
Thus, ``convert_to_non_blank_lines_of_words`` can be seen as having
|
||||
the type ``char list -> char list list list``.
|
||||
|
||||
We can use the type system to name new types that make this type
|
||||
easier to read.
|
||||
|
||||
First define the type ``word`` to be ``char list`` by
|
||||
```
|
||||
type word = char list
|
||||
```
|
||||
Then define a ``line`` type to be a ``word list``.
|
||||
|
||||
Then, we can specify that
|
||||
``convert_to_non_blank_lines_of_words`` has
|
||||
the type ``char list -> line list``.
|
||||
|
||||
In writing ``convert_to_non_blank_lines_of_words`` you may want to
|
||||
consider a helper function that breaks up a ``char
|
||||
list`` into lines, separated by new line characters (``'\n'``) and
|
||||
another that breaks up lines into lists of words.
|
||||
|
||||
|
||||
At this point you are not required to directly address the problems
|
||||
relating to capitalization of letters which we eventually need to
|
||||
address in checking that the same words appear in various parts of the
|
||||
poem. You are also not required to deal with issues of punctuation,
|
||||
but you may need to do something the be sure that words are correctly
|
||||
separated. For example, we would want to see ``that,barn`` as two
|
||||
words.
|
||||
|
||||
|
||||
## Part 3. The paradelle check.
|
||||
|
||||
We will now need to consider how punctuation is to be handled, how
|
||||
words are to be compared and, in the comparisons of lines, when
|
||||
duplicate words should be dropped and when they should not be.
|
||||
|
||||
We can now begin to write the function to check that a poem is a
|
||||
"paradelle".
|
||||
|
||||
To do this, write a function named ``paradelle`` that takes as input a
|
||||
filename (a ``string``) of a file containing a potential paradelle.
|
||||
This function then returns a value of the following type:
|
||||
```
|
||||
type result = OK
|
||||
| FileNotFound of string
|
||||
| IncorrectNumLines of int
|
||||
| IncorrectLines of (int * int) list
|
||||
| IncorrectLastStanza
|
||||
```
|
||||
This type describes the possible outcomes of the analysis. For example,
|
||||
1. ``OK``- The file contains a paradelle.
|
||||
1. ``FileNotFound "test.txt"`` - The file ``test.txt`` was not found.
|
||||
1. ``IncorrectNumLines 18`` - The file contained 18 lines after the
|
||||
blank lines were removed. A paradelle must have 24 lines.
|
||||
1. ``IncorrectLines [ (1,2); (11,12) ]`` - Lines 1 and 2 are not the
|
||||
same and thus this is not a paradelle. Also lines 11 and 12, in the
|
||||
second stanza, do not have the same words as in the first 4 lines
|
||||
of that stanza, and
|
||||
this is another reason why this one is not a paradelle.
|
||||
1. ``IncorrectLastStanza`` - the last stanza does not properly contain
|
||||
the words from the first three stanzas.
|
||||
|
||||
|
||||
**Remember, you are not to write any recursive functions.** Only
|
||||
``read_chars``, ``take``, and ``drop`` can be used.
|
||||
|
||||
|
||||
Furthermore, below is a list of functions from various OCaml modules
|
||||
that you may also use. Functions not in this list may not be used.
|
||||
(Except for functions such as ``input_char`` in functions that were
|
||||
given to you.)
|
||||
+ List.map, List.filter, List.fold_left, List.fold_right
|
||||
+ List.sort, List.concat,
|
||||
+ Char.lowercase, Char.uppercase
|
||||
+ string_of_int
|
||||
|
||||
The ``sort`` function takes comparison functions as its first argument.
|
||||
We saw how such functions are written and used in lecture.
|
||||
|
||||
These restrictions are in place so that you can see how interesting
|
||||
computations can be specified using the common idioms of mapping,
|
||||
filtering, and folding lists. The goal of this assignment is not
|
||||
simply to get the paradelle checker to work, but to get it to work and
|
||||
for you to understand how these higher order functions can be used.
|
||||
|
||||
|
||||
## Some advice.
|
||||
You will want to get started on this assignment sooner rather than
|
||||
later. There are many aspects that you need to think about. Most
|
||||
importantly is the structure of your program the various helper
|
||||
functions that you may want to use.
|
||||
|
||||
We recommend writing your helper functions at the "top level" instead
|
||||
of nested in a ``let`` expression so that you can inspect the type
|
||||
inferred for them by OCaml and also run them on sample input to check
|
||||
that they are correct.
|
||||
|
||||
|
||||
## Feedback tests.
|
||||
|
||||
Feedback tests are not initially turned on. You should read these
|
||||
specifications and make an effort to understand them based on the
|
||||
descriptions.
|
||||
|
||||
If you have questions, ask your TAs in lab or post them to the "Hwk
|
||||
02" forum on Moodle.
|
||||
|
||||
Feedback tests will be available next week.
|
||||
|
||||
|
43
public-class-repo/Homework/Hwk_02/hwk_02.ml
Normal file
43
public-class-repo/Homework/Hwk_02/hwk_02.ml
Normal file
|
@ -0,0 +1,43 @@
|
|||
(* This file contains a few helper functions and type declarations
|
||||
that are to be used in Homework 2. *)
|
||||
|
||||
(* Place part 1 functions 'take', 'drop', 'length', 'rev',
|
||||
'is_elem_by', 'is_elem', 'dedup', and 'split_by' here. *)
|
||||
|
||||
let rec take n l = match l with
|
||||
| [] -> []
|
||||
| x::xs -> if n > 0 then x::take (n-1) xs else []
|
||||
|
||||
let rec drop n l = match l with
|
||||
| [] -> []
|
||||
| x::xs -> if n > 0 then drop (n-1) xs else l
|
||||
|
||||
let rev lst = raise (Failure "This function is not yet implemented!")
|
||||
|
||||
|
||||
|
||||
(* Some functions for reading files. *)
|
||||
let read_file (filename:string) : char list option =
|
||||
let rec read_chars channel sofar =
|
||||
try
|
||||
let ch = input_char channel
|
||||
in read_chars channel (ch :: sofar)
|
||||
with
|
||||
| _ -> sofar
|
||||
in
|
||||
try
|
||||
let channel = open_in filename
|
||||
in
|
||||
let chars_in_reverse = read_chars channel []
|
||||
in Some (rev chars_in_reverse)
|
||||
with
|
||||
_ -> None
|
||||
|
||||
|
||||
|
||||
|
||||
type result = OK
|
||||
| FileNotFound of string
|
||||
| IncorrectNumLines of int
|
||||
| IncorrectLines of (int * int) list
|
||||
| IncorrectLastStanza
|
27
public-class-repo/Homework/Hwk_02/not_a_paradelle_emma_1.txt
Normal file
27
public-class-repo/Homework/Hwk_02/not_a_paradelle_emma_1.txt
Normal file
|
@ -0,0 +1,27 @@
|
|||
When Emma scrunches up her nose and knits her tiny brow,
|
||||
When Emma scrunches up her nose and knits her tiny brow,
|
||||
My granddaughter spins a happy web of hyphens that connect-her-eyes.
|
||||
My granddaughter spins a happy web of hyphens that connect-her-eyes.
|
||||
Connect her up, her brow, her nose, a web of Emma scrunches
|
||||
That, when granddaughter knits, spins tiny hyphens and my happy eyes.
|
||||
|
||||
But big-spring-sky-blues get old too fast, and early some time near
|
||||
But big-spring-sky-blues get old too fast, and early some time near
|
||||
Will dull as she forgets slow what we've already lost.
|
||||
Will dull as she forgets slow what we've already lost.
|
||||
As sky already forgets spring, we've but dull old blues, slow, fast
|
||||
And near, some big time. What, she will get lost early, too.
|
||||
|
||||
Her tousled-angel-twinkly-pouts accuse her hovering tutors.
|
||||
Her tousled-angel-twinkly-pouts accuse her hovering tutors.
|
||||
Her wise eyes smirk: here's to whatever we the grownups might recall.
|
||||
Her wise eyes smirk: here's to whatever we the grownups might recall.
|
||||
To angel eyes, we hovering grownups, smirk wise tutors, accuse:
|
||||
Here's her whatever, her tousled recall, her twinkly might, the pouts.
|
||||
|
||||
When old tutors smirk pouts, we've tousled her twinkly times.
|
||||
The wise get fast too early and slow her will some,
|
||||
And as granddaughter knits up that tiny nose, spins her brow of scrunches,
|
||||
She already near lost her might. Here's what big dull sky forgets:
|
||||
Spring blues, her happy eyes, her hyphens -------- , a web.
|
||||
But recall, my Emma, hovering angel eyes, connect to grownups, whatever we accuse.
|
|
@ -0,0 +1,27 @@
|
|||
I remember the quick, nervous bird of your love.
|
||||
I remember the, nervous bird of your love.
|
||||
Always perched on the thinnest, highest branch.
|
||||
Always perched on the thinnest, highest branch.
|
||||
Thinnest of love, remember the quick branch.
|
||||
Always nervous, I perched on your highest bird the.
|
||||
|
||||
It is time for me to cross the mountain.
|
||||
It is time for me to cross the mountain.
|
||||
And find another shore to darken with my pain.
|
||||
And find another shore to darken with my pain.
|
||||
Another pain for me to darken the mountain.
|
||||
And find the time, cross my shore, to with it is to.
|
||||
|
||||
The weather warm, the handwriting familiar.
|
||||
The weather warm, the handwriting familiar.
|
||||
Your letter flies from my hand into the waters below.
|
||||
Your letter flies from my hand into the waters below.
|
||||
The familiar waters below my warm hand.
|
||||
Into handwriting your weather flies your letter the from the.
|
||||
|
||||
I always cross the highest letter, the thinnest bird.
|
||||
Below the waters of my warm familiar pain,
|
||||
Another hand to remember your handwriting.
|
||||
The weather perched for me on the shore.
|
||||
Quick, your nervous branch flies for love.
|
||||
Darken the mountain, time and find my into it with from to to is.
|
|
@ -0,0 +1,27 @@
|
|||
I remember the quick, nervous bird of your love.
|
||||
I remember the quick, nervous bird of your love.
|
||||
Always perched on the thinnest, highest branch.
|
||||
Always perched on the thinnest, highest branch.
|
||||
Thinnest of love, remember the quick branch.
|
||||
Always nervous, I perched on your highest bird the.
|
||||
|
||||
It is time for me to cross the mountain.
|
||||
It is time for me to cross the mountain.
|
||||
And find another shore to darken with my pain.
|
||||
And find another shore to darken with my pain.
|
||||
Another pain for me to darken the mountain.
|
||||
And find the time, cross my shore, to with it is to.
|
||||
|
||||
The weather warm, the handwriting familiar.
|
||||
The weather warm, the handwriting familiar.
|
||||
Your letter flies from my hand into the waters below.
|
||||
Your letter flies from my hand into the waters below.
|
||||
The familiar waters below my warm hand.
|
||||
Into handwriting your weather flies your letter the from the.
|
||||
|
||||
I always cross the highest letter, the thinnest bird.
|
||||
Below the waters of my warm familiar pain,
|
||||
Another hand to remember your handwriting.
|
||||
The weather perched for me on the shore.
|
||||
Quick, your nervous branch flies for love.
|
||||
Darken the mountain, time and find my into it with from to is.
|
|
@ -0,0 +1,27 @@
|
|||
I remember the, nervous bird of your love.
|
||||
I remember the quick, nervous bird of your love.
|
||||
Always perched on the thinnest, highest branch.
|
||||
Always perched on the thinnest, highest branch.
|
||||
Thinnest of love, remember the quick branch.
|
||||
Always nervous, I perched on your highest bird the.
|
||||
|
||||
It is time for me to cross the mountain.
|
||||
It is time for me to cross the mountain.
|
||||
And find another shore to darken with my pain.
|
||||
And find another shore to darken with my pain.
|
||||
Another pain for me to darken the mountain.
|
||||
And find the time, cross my shore, to with it is to.
|
||||
|
||||
The weather warm, the handwriting familiar.
|
||||
The weather warm, the handwriting familiar.
|
||||
Your letter flies from my hand into the waters below.
|
||||
Your letter flies from my hand into the waters below.
|
||||
The familiar waters below my warm hand.
|
||||
Into handwriting your weather flies your letter the from the.
|
||||
|
||||
I always cross the highest letter, the thinnest bird.
|
||||
Below the waters of my warm familiar pain,
|
||||
Another hand to remember your handwriting.
|
||||
The weather perched for me on the shore.
|
||||
Quick, your nervous branch flies for love.
|
||||
Darken the mountain, time and find my into it with from to to is.
|
|
@ -0,0 +1,11 @@
|
|||
When Emma scrunches up her nose and knits her tiny brow,
|
||||
When Emma scrunches up her nose and knits her tiny brow,
|
||||
My granddaughter spins a happy web of hyphens that connect-her-eyes.
|
||||
My granddaughter spins a happy web of hyphens that connect-her-eyes.
|
||||
Connect her up, her brow, her nose, a web of Emma scrunches
|
||||
That, when granddaughter knits, spins tiny hyphens and my happy eyes.
|
||||
|
||||
But big-spring-sky-blues get old too fast, and early some time near
|
||||
But big-spring-sky-blues get old too fast, and early some time near
|
||||
Will dull as she forgets slow what we've already lost.
|
||||
|
27
public-class-repo/Homework/Hwk_02/paradelle_emma_1.txt
Normal file
27
public-class-repo/Homework/Hwk_02/paradelle_emma_1.txt
Normal file
|
@ -0,0 +1,27 @@
|
|||
When Emma scrunches up her nose and knits her tiny brow,
|
||||
When Emma scrunches up her nose and knits her tiny brow,
|
||||
My granddaughter spins a happy web of hyphens that connect-her-eyes.
|
||||
My granddaughter spins a happy web of hyphens that connect-her-eyes.
|
||||
Connect her up, her brow, her nose, a web of Emma scrunches
|
||||
That, when granddaughter knits, spins tiny hyphens and my happy eyes.
|
||||
|
||||
But big-spring-sky-blues get old too fast, and early some time near
|
||||
But big-spring-sky-blues get old too fast, and early some time near
|
||||
Will dull as she forgets slow what we've already lost.
|
||||
Will dull as she forgets slow what we've already lost.
|
||||
As sky already forgets spring, we've but dull old blues, slow, fast
|
||||
And near, some big time. What, she will get lost early, too.
|
||||
|
||||
Her tousled-angel-twinkly-pouts accuse her hovering tutors.
|
||||
Her tousled-angel-twinkly-pouts accuse her hovering tutors.
|
||||
Her wise eyes smirk: here's to whatever we the grownups might recall.
|
||||
Her wise eyes smirk: here's to whatever we the grownups might recall.
|
||||
To angel eyes, we hovering grownups, smirk wise tutors, accuse:
|
||||
Here's her whatever, her tousled recall, her twinkly might, the pouts.
|
||||
|
||||
When old tutors smirk pouts, we've tousled her twinkly time.
|
||||
The wise get fast too early and slow her will some,
|
||||
And as granddaughter knits up that tiny nose, spins her brow of scrunches,
|
||||
She already near lost her might. Here's what big dull sky forgets:
|
||||
Spring blues, her happy eyes, her hyphens -------- , a web.
|
||||
But recall, my Emma, hovering angel eyes, connect to grownups, whatever we accuse.
|
27
public-class-repo/Homework/Hwk_02/paradelle_susan_1.txt
Normal file
27
public-class-repo/Homework/Hwk_02/paradelle_susan_1.txt
Normal file
|
@ -0,0 +1,27 @@
|
|||
I remember the quick, nervous bird of your love.
|
||||
I remember the quick, nervous bird of your love.
|
||||
Always perched on the thinnest, highest branch.
|
||||
Always perched on the thinnest, highest branch.
|
||||
Thinnest of love, remember the quick branch.
|
||||
Always nervous, I perched on your highest bird the.
|
||||
|
||||
It is time for me to cross the mountain.
|
||||
It is time for me to cross the mountain.
|
||||
And find another shore to darken with my pain.
|
||||
And find another shore to darken with my pain.
|
||||
Another pain for me to darken the mountain.
|
||||
And find time, cross my shore, to with it is.
|
||||
|
||||
The weather warm, the handwriting familiar.
|
||||
The weather warm, the handwriting familiar.
|
||||
Your letter flies from my hand into the waters below.
|
||||
Your letter flies from my hand into the waters below.
|
||||
The familiar waters below my warm hand.
|
||||
Into handwriting, weather flies your letter the from the.
|
||||
|
||||
I always cross the highest letter, the thinnest bird.
|
||||
Below the waters of my warm familiar pain,
|
||||
Another hand to remember your handwriting.
|
||||
The weather perched for me on the shore.
|
||||
Quick, your nervous branch flies for love.
|
||||
Darken the mountain, time and find my into it with from to to is.
|
31
public-class-repo/Homework/Hwk_02/paradelle_susan_2.txt
Normal file
31
public-class-repo/Homework/Hwk_02/paradelle_susan_2.txt
Normal file
|
@ -0,0 +1,31 @@
|
|||
|
||||
I remember the quick, nervous bird of your love.
|
||||
I remember the quick, nervous bird of your love.
|
||||
Always perched on the thinnest, highest branch.
|
||||
Always perched on the thinnest,highest branch.
|
||||
Thinnest of love, remember the quick branch.
|
||||
Always nervous, I perched on your highest bird the.
|
||||
|
||||
|
||||
It is time for me to Cross the mountain.
|
||||
It is time for me to cross the mountain.
|
||||
And find another shore to darken with my pain.
|
||||
And find another shore to darken with my pain.
|
||||
Another pain for me to darken the mountain.
|
||||
And find time, cross my shore, to with it is.
|
||||
|
||||
|
||||
The weather warm, the handwriting familiar.
|
||||
The weather warm, the handwriting familiar.
|
||||
Your letter flies from my hand into the waters below.
|
||||
Your letter flies from my hand into the waters below.
|
||||
The familiar waters below my warm hand.
|
||||
Into handwriting, weather flies your letter the from the.
|
||||
|
||||
|
||||
I always cross the highest letter, the thinnest bird.
|
||||
Below the waters of my warm familiar pain,
|
||||
Another hand to remember your handwriting.
|
||||
The weather perched for me on the shore.
|
||||
Quick, your nervous branch flies for love.
|
||||
Darken the mountain, time and find my into it with from to to is.
|
4
public-class-repo/Homework/Hwk_03.md
Normal file
4
public-class-repo/Homework/Hwk_03.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
|
||||
## Homework 3.
|
||||
|
||||
See the PDF file ``Hwk_03.pdf`` for instruction on homework 3.
|
BIN
public-class-repo/Homework/Hwk_03.pdf
Normal file
BIN
public-class-repo/Homework/Hwk_03.pdf
Normal file
Binary file not shown.
517
public-class-repo/Homework/Hwk_04.md
Normal file
517
public-class-repo/Homework/Hwk_04.md
Normal file
|
@ -0,0 +1,517 @@
|
|||
# Homework 4: Programs as Data.
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
**Due:** Wednesday, March 22 at 5:00pm.
|
||||
|
||||
## Introduction
|
||||
|
||||
In this assignment you'll write a few functions that work with
|
||||
inductive values representing expressions for a small subset of
|
||||
OCaml.
|
||||
|
||||
In part 1 your functions will convert arithmetic expressions
|
||||
into strings, in an easy way and then in a way that doesn't generate
|
||||
unnecessary parenthesis.
|
||||
|
||||
In part 2 you'll write an evaluation function the computes the value
|
||||
of an expression. But these expressions may define and use recursive
|
||||
functions so they are computationally interesting.
|
||||
|
||||
I expect that this assignment may take up to 10 or 12 hours to
|
||||
complete, if not more. So you should start early and not wait until
|
||||
after spring break to begin. Be sure to get the help you may need
|
||||
from TAs before spring break.
|
||||
|
||||
There is plenty of time to do this work if you start now. The due
|
||||
date will not be pushed back.
|
||||
|
||||
|
||||
## Getting started
|
||||
|
||||
## Part 1 - arithmetic expressions as strings
|
||||
|
||||
To begin this component, copy the file ``arithmetic.ml`` from
|
||||
the directory ``Homework/Hwk_04`` in the public class repository and
|
||||
place it in a directory named ``Hwk_04`` in your repository.
|
||||
|
||||
|
||||
### Simple "unparsing"
|
||||
|
||||
Consider the following type for expressions. We've used variants of
|
||||
this in class for a number of examples:
|
||||
```
|
||||
type expr
|
||||
= Const of int
|
||||
| Add of expr * expr
|
||||
| Mul of expr * expr
|
||||
| Sub of expr * expr
|
||||
| Div of expr * expr
|
||||
```
|
||||
This type definition can be found in ``arithmetic.ml``.
|
||||
|
||||
Write a function named ``show_expr`` that converts an ``expr`` value
|
||||
into a ``string`` representation using traditional infix symbols for
|
||||
the operators. The output of this function should be something you
|
||||
could copy and paste into the OCaml interpreter and have it evaluate
|
||||
to the expected value.
|
||||
|
||||
Addition, multiplication, subtraction, and division
|
||||
should be wrapped in parenthesis so that the generated string
|
||||
represents the same expression as the input ``expr`` value.
|
||||
Constants, however, should not be wrapped in parenthesis.
|
||||
|
||||
Your function must include type annotations indicate the types of the
|
||||
arguments and the return type.
|
||||
|
||||
Here are some example evaluations of ``show_expr``:
|
||||
+ ``show_expr (Add(Const 1, Const 3))`` evaluates to ``"(1+3)"``
|
||||
|
||||
+ ``show_expr (Add (Const 1, Mul (Const 3, Const 4)))`` evaluates to ``"(1+(3*4))"``
|
||||
|
||||
+ ``show_expr (Mul (Add(Const 1, Const 3), Div(Const 8, Const 4)))`` evaluates to ``"((1+3)*(8/4))"``
|
||||
|
||||
|
||||
### Pretty-printing expressions
|
||||
|
||||
While the function ``show_expr`` should create legal expression
|
||||
strings, they often have extra parenthesis that are not needed to
|
||||
understand the meaning of the expression. This
|
||||
problem asks you to write a similar function named
|
||||
``show_pretty_expr`` that does not create any unnecessary parenthesis.
|
||||
|
||||
A pair of parenthesis, that is a matching "(" and ")", in
|
||||
a string representation of an expression are unnecessary if the value
|
||||
of the expression with the parenthesis and the value of the expression
|
||||
without the parenthesis are the same.
|
||||
|
||||
Consider the following example using ``show_expr``:
|
||||
+ ``show_expr (Add (Const 1, Mul (Const 3, Const 4)))``
|
||||
evaluates to ``"(1+(3*4))"``
|
||||
|
||||
The parenthesis around the product "3*4" are not necessary. Neither
|
||||
are the parenthesis around the entire expression.
|
||||
|
||||
However, in the following case
|
||||
+ ``show_expr (Mul (Const 4, Add (Const 3, Const 2)))``
|
||||
evaluates to ``"(4*(3+2))"``
|
||||
|
||||
The inner parenthesis around ``3+2`` are needed. Again, the outer
|
||||
parenthesis are not needed. This is because multiplication has higher
|
||||
precedence than addition.
|
||||
|
||||
These examples illustrate that an expression needs to be wrapped
|
||||
in parenthesis if its operator's precedence is lower than the
|
||||
operator of the expression containing it.
|
||||
|
||||
We think of operator precedence as being equal to, lower than,
|
||||
or higher than the precedence of other operators. This suggest that
|
||||
we use integers to represent the precedence of different operators.
|
||||
|
||||
We must also consider the associativity of an operation. Consider this
|
||||
``expr`` value and the result of applying ``show_expr`` to it.
|
||||
|
||||
+ ``show_expr (Sub (Sub (Const 1, Const 2), Sub (Const 3, Const 4)))``
|
||||
evaluates to ``"((1-2)-(3-4))"``
|
||||
|
||||
Note that since subtraction is left associative (a value between two
|
||||
subtraction operators is associated with the one to its left) the
|
||||
parenthesis around ``1-2`` are not needed, but those around ``3-4``
|
||||
are needed.
|
||||
|
||||
All operations represented in our ``expr`` type are left associative.
|
||||
So when the enclosing operator has the same precedence, it may suffice
|
||||
for an expression to know if it should be wrapped in parenthesis or
|
||||
not, by knowing if it is the left child or right child (if either) of
|
||||
the expression that it is a component of.
|
||||
|
||||
Of course in some cases, such as at the root of the expression, it
|
||||
might not be a component of a binary operator.
|
||||
|
||||
|
||||
Write a function ``show_pretty_expr`` that generates a ``string``
|
||||
representation of an ``expr`` similar to ``show_expr`` but without any
|
||||
unnecessary parenthesis. In doing so, write appropriate helper
|
||||
functions to avoid an overabundance of copy-and-pasted code fragments
|
||||
that are non-trivial near exact copies of one another.
|
||||
|
||||
Also, be sure to use disjoint union types where appropriate. While
|
||||
integers are appropriate for representing precedence of operators,
|
||||
they may not be appropriate in dealing with issues of associativity.
|
||||
|
||||
A few more sample evaluations:
|
||||
+ ``show_pretty_expr (Add (Const 1, Mul (Const 3, Const 4)))``
|
||||
evaluates to ``"1+3*4"``
|
||||
|
||||
+ ``show_pretty_expr (Add (Mul (Const 1, Const 3), Const 4))``
|
||||
evaluates to ``"1*3+4"``
|
||||
|
||||
+ ``show_pretty_expr (Add (Const 1, Add (Const 3, Const 4)))``
|
||||
evaluates to ``"1+(3+4)"``
|
||||
|
||||
+ ``show_pretty_expr (Add (Add (Const 1, Const 3), Const 4))``
|
||||
evaluates to ``"1+3+4"``
|
||||
|
||||
+ ``show_pretty_expr (Mul (Const 4, Add (Const 3, Const 2)))``
|
||||
evaluates to ``"4*(3+2)"``
|
||||
|
||||
+ ``show_pretty_expr (Sub (Sub (Const 1, Const 2), Sub (Const 3, Const 4)))``
|
||||
evaluates to ``"1-2-(3-4)"``
|
||||
|
||||
|
||||
It should be clear that ``show_pretty_expr`` cannot be a simple
|
||||
recursive function with only an ``expr`` as input and a ``string`` as
|
||||
output. Nested expressions will likely need to know what kind of
|
||||
expression they are nested in, and maybe other information as well.
|
||||
Thus ``show_pretty_expr`` will likely call another function that has
|
||||
additional inputs that actually does the work of constructing the
|
||||
string. Determining what this additional information is and how it is
|
||||
passed around in the function calls is the interesting part of this
|
||||
exercise.
|
||||
|
||||
|
||||
## Part 2 - evaluation of expressions with functional values
|
||||
|
||||
In class we've written bits and pieces of evalutors for different
|
||||
kinds of expressions with different kinds or representations for
|
||||
values.
|
||||
|
||||
In this part of the assignment we pull all these pieces together to
|
||||
build an interpreter for a small but computationally powerful subset
|
||||
of OCaml.
|
||||
|
||||
For this part of the assignment you will implement a function named
|
||||
``evaluate`` that has the type ``expr -> value``.
|
||||
|
||||
The type for ``expr`` is provided below and an incomplete
|
||||
specification for the type ``value`` is also given.
|
||||
|
||||
```
|
||||
type expr
|
||||
= Add of expr * expr
|
||||
| Sub of expr * expr
|
||||
| Mul of expr * expr
|
||||
| Div of expr * expr
|
||||
|
||||
| Lt of expr * expr
|
||||
| Eq of expr * expr
|
||||
| And of expr * expr
|
||||
|
||||
| If of expr * expr * expr
|
||||
|
||||
| Id of string
|
||||
|
||||
| Let of string * expr * expr
|
||||
| LetRec of string * expr * expr
|
||||
|
||||
| App of expr * expr
|
||||
| Lambda of string * expr
|
||||
|
||||
| Value of value
|
||||
|
||||
and value
|
||||
= Int of int
|
||||
| Bool of bool
|
||||
| Closure of string * expr * environment
|
||||
```
|
||||
|
||||
To begin this component, copy the file ``eval.ml`` from
|
||||
the directory ``Homework/Hwk_04`` and place it in a directory named
|
||||
``Hwk_04`` in your repository. That file has the type definitions
|
||||
given above.
|
||||
|
||||
|
||||
### Step 1 - determining the free variables in an expression
|
||||
|
||||
To get started with this richer form of expressions write a function
|
||||
named ``freevars`` that has the type ``expr -> string list``.
|
||||
|
||||
This function will, as the name suggests, return the list of free
|
||||
variables that appear in an expression. These are the names that are
|
||||
not "bound" by a let-expression or a by a lambda-expression.
|
||||
|
||||
Note that we also have a "let-rec" expression that we will be using
|
||||
for recursive functions. It is intended to have the same semantics as
|
||||
the ``let rec`` construct in OCaml. For this constucts, the free
|
||||
variables are those found in either of the two component expressions,
|
||||
except that we don't include the name bound by the let-rec in the list
|
||||
of names that are returned.
|
||||
|
||||
Consider these sample evaluations of a correct implementation of
|
||||
``freevars``:
|
||||
|
||||
+ ``freevars (Add (Value (Int 3), Mul (Id "x", Id "y")))``
|
||||
evaluates to ``["x"; "y"]``
|
||||
|
||||
+ ``freevars (Let ("x", Id "z", Add (Value (Int 3), Mul (Id "x", Id "y")))`)`
|
||||
evaluates to ``["z"; "y"]``
|
||||
|
||||
+ ``freevars (Let ("x", Id "x", Add (Value (Int 3), Mul (Id "x", Id "y")))`)`
|
||||
evaluates to ``["x"; "y"]``
|
||||
|
||||
+ ``freevars (Lambda ("x", Add (Value (Int 3), Mul (Id "x", Id "y"))))``
|
||||
evaluates to ``["y"]``
|
||||
|
||||
+ ``freevars sumToN_expr``
|
||||
evaluates to ``[]``
|
||||
|
||||
where ``sumToN_expr`` is as defined at the end of this file and in the
|
||||
``eval.ml`` file you copied from the public repository.
|
||||
|
||||
|
||||
### Step 2 - environments
|
||||
|
||||
The function that the tests will call must be named
|
||||
``evaluate`` and must have the type ``expr -> value``. You will need
|
||||
to use environments in this work in a manner similar to what we did in
|
||||
some of the in-class examples. Thus you might write a helper function
|
||||
called ``eval`` that can take any extra needed arguments to actually
|
||||
perform the evaluation.
|
||||
|
||||
|
||||
### Step 3 - arithmetic expressions
|
||||
|
||||
To get stared, first ensure that ``evaluate`` will work for the
|
||||
arithmetic operations and integer constants. Much of the work for this
|
||||
has been done in some of the in-class example already.
|
||||
|
||||
An example evaluation:
|
||||
|
||||
+ ``evaluate (Add (Value (Int 1), Mul (Value (Int 2), Value (Int 3))))``
|
||||
evaluates to ``Int 7``
|
||||
|
||||
|
||||
|
||||
### Step 4 - logical and relational expressions
|
||||
|
||||
Logical and relational operations are also straightforward:
|
||||
|
||||
Some sample evaluations:
|
||||
|
||||
+ ``evaluate (Eq (Value (Int 1), Mul (Value (Int 2), Value (Int 3))))``
|
||||
evaluates to ``Bool false``
|
||||
|
||||
+ ``evaluate (Lt (Value (Int 1), Mul (Value (Int 2), Value (Int 3))))``
|
||||
evaluates to ``Bool true``
|
||||
|
||||
### Step 5 - conditional expressions
|
||||
Conditional expressions should also pose not significant challenge.
|
||||
For example
|
||||
|
||||
```
|
||||
evaluate
|
||||
(If (Lt (Value (Int 1), Mul (Value (Int 2), Value (Int 3))),
|
||||
Value (Int 4),
|
||||
Value (Int 5)))
|
||||
```
|
||||
|
||||
evaluates to ``Int 4 ``
|
||||
|
||||
|
||||
|
||||
### Step 6 let expressions
|
||||
We've implemented non-recursive let-expressions in a forms in
|
||||
class. Adapting that work to this setting should be straightforward.
|
||||
|
||||
|
||||
|
||||
### Step 7 - non-recursive functions
|
||||
We've spent some time in class discussing closures as the way to
|
||||
represent the value of a lambda expression. The slides have several
|
||||
examples of this, a few of which are reproduced here.
|
||||
|
||||
The values ``inc`` and ``add`` are defined as follows:
|
||||
```
|
||||
let inc = Lambda ("n", Add(Id "n", Value (Int 1)))
|
||||
|
||||
let add = Lambda ("x",
|
||||
Lambda ("y", Add (Id "x", Id "y"))
|
||||
)
|
||||
```
|
||||
|
||||
Some sample evaluations:
|
||||
|
||||
+ ``evaluate inc``
|
||||
evaluates to ``Closure ("n", Add (Id "n", Value (Int 1)), [])``
|
||||
|
||||
+ ``evaluate add``
|
||||
evaluates to ``Closure ("x", Lambda ("y", Add (Id "x", Id "y")), [])``
|
||||
|
||||
+ ``evaluate (App (add, Value (Int 1)))``
|
||||
evaluates to ``Closure ("y", Add (Id "x", Id "y"), [("x", Int 1)])``
|
||||
|
||||
+ ``evaluate (App ( (App (add, Value (Int 1))), Value (Int 2)))``
|
||||
evaluates to ``Int 3``
|
||||
|
||||
|
||||
### Step 8 - recursive functions
|
||||
|
||||
Consider the ``sumToN`` function we discussed in class. In OCaml,
|
||||
we'd write this function as follows:
|
||||
```
|
||||
let rec sumToN = fun n ->
|
||||
if n = 0 then 0 else n + sumToN (n-1)
|
||||
in sumToN 4
|
||||
```
|
||||
To represent this function in our mini-OCaml language defined by the
|
||||
``expr`` type, we'd represent the function as follows:
|
||||
```
|
||||
let sumToN_expr : expr =
|
||||
LetRec ("sumToN",
|
||||
Lambda ("n",
|
||||
If (Eq (Id "n", Value (Int 0)),
|
||||
Value (Int 0),
|
||||
Add (Id "n",
|
||||
App (Id "sumToN",
|
||||
Sub (Id "n", Value (Int 1))
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
Id "sumToN"
|
||||
)
|
||||
```
|
||||
Here we've given the name ``sumToN_expr`` to the ``expr`` value that
|
||||
represent our ``sumToN`` function.
|
||||
|
||||
|
||||
+ ``evaluate (App (sumToN_expr, Value (Int 10)))``
|
||||
evaluates to ``Int 55``
|
||||
|
||||
|
||||
|
||||
### Handling ill-formed expressions
|
||||
|
||||
#### Type errors
|
||||
|
||||
Expressions, that is values of type ``expr``, do not necessarily
|
||||
represent well-typed programs.
|
||||
|
||||
For example,
|
||||
```
|
||||
Add (Value (Int 4), Value (Bool true))
|
||||
```
|
||||
is type-correct OCaml code, but it represents an expression that is
|
||||
not type-correct.
|
||||
|
||||
Your evaluation function should handle type errors like this by
|
||||
raising an exception of type ``Failure`` whose string component has
|
||||
the phrase "incompatible types".
|
||||
|
||||
For example
|
||||
|
||||
+ ``evaluate (Add (Value (Int 4), Value (Bool true)))``
|
||||
raises the exception ``Exception: Failure "incompatible types, Add".``
|
||||
|
||||
In the reference solution, this is accomplished by evaluating this
|
||||
expression:
|
||||
```
|
||||
raise (Failure "incompatible types on Add")
|
||||
```
|
||||
|
||||
Your solution should generate messages for ``Failure`` exceptions that
|
||||
have this form: "incompatible types on AAA" where AAA is replaced by
|
||||
the
|
||||
constructor name that is used in the type ``expr``
|
||||
|
||||
Similar exceptions should be raised for other type errors on other
|
||||
constructors such as ``Mul``, ``Lt``, ``If``, etc.
|
||||
|
||||
|
||||
#### Unbound identifiers
|
||||
|
||||
Expressions may also have free variable and evaluating these should
|
||||
raise an exception as well.
|
||||
|
||||
For example,
|
||||
+ ``evaluate (Add (Id "x", Value (Int 3)))``
|
||||
should raise a ``Failure`` exception with the phrase "x not in
|
||||
scope". If the name was "y" then the phrase should be "y not in
|
||||
scope.
|
||||
|
||||
|
||||
#### Recursive let expressions
|
||||
|
||||
Recursive let expressions should only bind names to lambda
|
||||
expressions.
|
||||
|
||||
That is, ``expr`` values of the form
|
||||
```
|
||||
LetRec (_, Lambda (_, _), )
|
||||
```
|
||||
are valid, but a ``LetRec`` that does not have a ``Lambda`` as the
|
||||
expression as its second component is considered invalid.
|
||||
|
||||
If this invalid form of expression is evaluated then your solution
|
||||
should raise a ``Failure`` exception with the message containing the
|
||||
phrase "let rec expressions must declare a function".
|
||||
|
||||
|
||||
|
||||
## Part 3 - Optional next steps
|
||||
|
||||
If you are interested in developing these ideas further you are
|
||||
encouraged to attempt the following problems.
|
||||
|
||||
### Static error detection - type checking
|
||||
|
||||
Instead of raising an exception when an ill-formed expression, of the
|
||||
type described above, we could instead do some so-called static
|
||||
analysis of the expressions to detect the problems *before* evaluating
|
||||
it.
|
||||
|
||||
One way to detect type errors is to do what is called type checking.
|
||||
In this approach we would extend the ``Lambda``, ``Let``, and
|
||||
``LetRec`` constructors so that some indication of the type of the
|
||||
name being introduced is part of these constructors.
|
||||
|
||||
For example, we may indicate that a name ``x`` is to have integer type
|
||||
in a let with the following:
|
||||
```
|
||||
Let ("x", IntType, Value (Int 4), Add (Id "x", Value (Int 5)))
|
||||
```
|
||||
Similar annotations would be needed for the other mentioned
|
||||
constructors.
|
||||
|
||||
With this information in the representation of the expression can you
|
||||
write a function the checks for the above mentioned forms of invalid
|
||||
expressions without evaluating them?
|
||||
|
||||
What would this function return?
|
||||
|
||||
### Static error detection - type inference
|
||||
|
||||
How might we statically detect this kinds of errors but without adding
|
||||
the type annotations described above. That is, using the existing
|
||||
definition of `expr` can we detect possible type errors statically?
|
||||
|
||||
A correct solution to either of these static error detection problems
|
||||
would give a guarantee that if no static errors are reported, then
|
||||
during evaluation there will be no type errors, regardless of the
|
||||
input.
|
||||
|
||||
|
||||
### More interesting data structures
|
||||
|
||||
Can you extend ``expr`` and ``value`` to support lists and tuples as
|
||||
they are found in OCaml?
|
||||
|
||||
Can you extend your type checking or type inference solutions to work
|
||||
with these new constructs?
|
||||
|
||||
### Turning in your work
|
||||
|
||||
If you do want to try these problems, create a file (of files) for
|
||||
your solution that is different from the ``eval.ml`` solution that
|
||||
will be the basis of our assessment of the required parts of this
|
||||
problem.
|
||||
|
||||
Any solution must come with significant documentation explaining what
|
||||
it is that you've done and how your solution works.
|
||||
|
||||
Doing this work may improve your grade in this course, but there is no
|
||||
guarantee of that. You attempt these problems because you find the
|
||||
problems interesting and challenging - not because you want to improve
|
||||
your grade.
|
||||
|
||||
|
7
public-class-repo/Homework/Hwk_04/arithmetic.ml
Normal file
7
public-class-repo/Homework/Hwk_04/arithmetic.ml
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
type expr
|
||||
= Const of int
|
||||
| Add of expr * expr
|
||||
| Mul of expr * expr
|
||||
| Sub of expr * expr
|
||||
| Div of expr * expr
|
62
public-class-repo/Homework/Hwk_04/eval.ml
Normal file
62
public-class-repo/Homework/Hwk_04/eval.ml
Normal file
|
@ -0,0 +1,62 @@
|
|||
type expr
|
||||
= Add of expr * expr
|
||||
| Sub of expr * expr
|
||||
| Mul of expr * expr
|
||||
| Div of expr * expr
|
||||
|
||||
| Lt of expr * expr
|
||||
| Eq of expr * expr
|
||||
| And of expr * expr
|
||||
|
||||
| If of expr * expr * expr
|
||||
|
||||
| Id of string
|
||||
|
||||
| Let of string * expr * expr
|
||||
| LetRec of string * expr * expr
|
||||
|
||||
| App of expr * expr
|
||||
| Lambda of string * expr
|
||||
|
||||
| Value of value
|
||||
|
||||
and value
|
||||
= Int of int
|
||||
| Bool of bool
|
||||
| Closure of string * expr * environment
|
||||
(* You may need an extra constructor for this type. *)
|
||||
|
||||
|
||||
|
||||
|
||||
let evaluate (e:expr) : value =
|
||||
raise (Failure "Complete this function...")
|
||||
|
||||
|
||||
|
||||
(* Some sample expressions *)
|
||||
|
||||
let inc = Lambda ("n", Add(Id "n", Value (Int 1)))
|
||||
|
||||
let add = Lambda ("x",
|
||||
Lambda ("y", Add (Id "x", Id "y"))
|
||||
)
|
||||
|
||||
(* The 'sumToN' function *)
|
||||
let sumToN_expr : expr =
|
||||
LetRec ("sumToN",
|
||||
Lambda ("n",
|
||||
If (Eq (Id "n", Value (Int 0)),
|
||||
Value (Int 0),
|
||||
Add (Id "n",
|
||||
App (Id "sumToN",
|
||||
Sub (Id "n", Value (Int 1))
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
Id "sumToN"
|
||||
)
|
||||
|
||||
|
||||
let twenty_one : value = evaluate (App (sumToN_expr, Value (Int 6)));
|
317
public-class-repo/Homework/Hwk_05.md
Normal file
317
public-class-repo/Homework/Hwk_05.md
Normal file
|
@ -0,0 +1,317 @@
|
|||
# Homework 5: Lazy Evaluation
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
**Due:** 5pm Wednesday, April 5
|
||||
|
||||
|
||||
## Part 1: Expression evaluation by-hand
|
||||
|
||||
In class, and demonstrated in the document "Expression Evaluation
|
||||
Examples" on Moodle, we have evaluated expressions by hand, step by
|
||||
step, to understand the different ways in which call by value
|
||||
semantics, call by name semantics, and lazy evaluation work.
|
||||
|
||||
#### Question 1
|
||||
|
||||
Consider the following definitions:
|
||||
```
|
||||
sum [] = 0
|
||||
sum x::xs -> x + sum xs
|
||||
|
||||
take 0 lst = [ ]
|
||||
take n [ ] = [ ]
|
||||
take n (x::xs) = x::take (n-1) xs
|
||||
|
||||
some_squares_from 0 v = [ ]
|
||||
some_squares_from n v = v*v :: some_squares_from (n-1) (v+1)
|
||||
```
|
||||
|
||||
Evaluate
|
||||
```
|
||||
sum (take 3 (some_squares_from 5 1))
|
||||
```
|
||||
using call by value semantics, call by name semantics, and lazy
|
||||
evaluation.
|
||||
|
||||
Each of these three evaluations must be clearly labeled with the form
|
||||
of evaluation used.
|
||||
|
||||
Furthermore, all must be produced electronically. No handwritten work
|
||||
will be accepted. You may use a text editor and turn in a text file.
|
||||
These are relatively simple so there is no need to use MarkDown or
|
||||
generate a PDF file.
|
||||
|
||||
Your name and University Internet ID must appear in the upper left of
|
||||
the document.
|
||||
|
||||
Name this file ``question_1.txt`` and place it in a directory named
|
||||
``Hwk_05`` in your GitHub repository.
|
||||
|
||||
|
||||
|
||||
#### Question 2
|
||||
|
||||
Recall our definitions for ``foldl`` and ``foldr`` as well as the
|
||||
functions for folding ``and`` over a list of boolean values. (Note
|
||||
that we removed the underscores from the names as they appeared on the
|
||||
slides.)
|
||||
```
|
||||
foldr f [] v = v
|
||||
foldr f (x::xs) v = f x (foldr f xs v)
|
||||
|
||||
foldl f v [] = v
|
||||
foldl f v (x::xs) = foldl f (f v x) xs
|
||||
|
||||
and b1 b2 = if b1 then b2 else false
|
||||
|
||||
andl l = foldl and true l
|
||||
andr l = foldr and l true
|
||||
```
|
||||
|
||||
You are asked to evaluate the expressions
|
||||
```
|
||||
andl (t::f::t::t::[])
|
||||
```
|
||||
and
|
||||
```
|
||||
andr (t::f::t::t::[])
|
||||
```
|
||||
using both call by value and call by name semantics.
|
||||
|
||||
A few things to note:
|
||||
|
||||
+ Since anytime a function uses an argument more than once
|
||||
(this only happens with ``f`` in the two fold functions) it is given
|
||||
a value and not an unevaluated expression, there is no benefit from
|
||||
the optimization we get with lazy evaluation. So we don't need to
|
||||
consider it here.
|
||||
|
||||
+ To save space we are not spelling out the full name of the values
|
||||
``true`` and ``false`` but are instead abbreviating them here as
|
||||
``t`` and ``f``. Do not consider these to be variables! They are
|
||||
the boolean literals for true and false. You may do the same in
|
||||
your homework.
|
||||
|
||||
+ Lists are written in their basic form using the cons (``::``) and
|
||||
nil (``[]``) operators instead of the syntactic sugar form using
|
||||
semicolons to separate lists values between square brackets.
|
||||
|
||||
|
||||
Clearly label each evaluation with the kind of semantics used for it.
|
||||
|
||||
After you have completed all four of them, explain which one is the
|
||||
most efficient and why.
|
||||
|
||||
Each of these three evaluations must be clearly labeled with the form
|
||||
of evaluation used.
|
||||
|
||||
Furthermore, all must be produced electronically. No handwritten work
|
||||
will be accepted. As before, you may use a text editor and turn in a
|
||||
text file.
|
||||
|
||||
Your name and University Internet ID must appear in the upper left of
|
||||
the document.
|
||||
|
||||
Name this file ``question_2.txt`` and place it
|
||||
in the ``Hwk_05`` directory your created for question 1.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Part 2: Efficiently computing the conjunction of a list of boolean values in OCaml
|
||||
|
||||
Write an OCaml function named ``ands`` with the type
|
||||
``bool list -> bool`` that computes the same result as the
|
||||
``andl`` and ``andr`` functions described in the problem above.
|
||||
|
||||
Your OCaml function should be written so that it does not examine or
|
||||
traverse the entire list if it does not need to. We saw this behavior
|
||||
in one of the by-hand evaluations above. If a ``false`` value is
|
||||
encountered then it the computation can terminate and return
|
||||
``false``.
|
||||
|
||||
|
||||
This function should, following the pattern of past assignments, be
|
||||
placed in a file named ``hwk_05.ml``. This file must be placed in a
|
||||
directory named ``Hwk_05`` in your GitHub repository.
|
||||
|
||||
|
||||
|
||||
## Part 3: Implementing Streams in OCaml
|
||||
|
||||
In class, and demonstrated in the file ``streams.ml`` in the
|
||||
code-examples directory of the public repositories, we developed a
|
||||
type constructor ``stream`` that can be used to create lazy streams
|
||||
and make use of lazy evaluation techniques in a strict/eager language.
|
||||
|
||||
Below you are asked to define a collection of stream values and
|
||||
functions over streams.
|
||||
|
||||
To start this part of the assignment, first copy the ``streams.ml``
|
||||
file into your ``Hwk_05`` directory. Add the following functions to
|
||||
the end of that file. But you should clearly mark the parts of this
|
||||
file that you did not write and attribute them to their author (your
|
||||
instructor) and then indicate where your work starts in the file by
|
||||
adding you name and a comment to this effect.
|
||||
|
||||
#### ``cubes_from``
|
||||
|
||||
Define a function ``cubes_from`` with the type ``int -> int stream``
|
||||
that creates a stream of the cubes of numbers starting with the
|
||||
input value. For example, ``cubes_from 5`` should return a stream
|
||||
that contains the values 125, 216, 343, ...
|
||||
|
||||
Demonstrate to yourself that this work by using ``take`` to generate a
|
||||
finite number of cubes.
|
||||
|
||||
#### ``drop``
|
||||
|
||||
Write a function named ``drop`` with the type ``int -> 'a stream -> 'a
|
||||
stream``. This function is the stream version of the ``drop``
|
||||
function that you've written for lists. Note the difference of the
|
||||
type for ``drop`` for that of ``take`` over lists. Since ``take``
|
||||
will remove a finite number of elements from a stream we have decided
|
||||
to store them in a list instead.
|
||||
|
||||
#### ``drop_until``
|
||||
|
||||
Write a function named ``drop_until`` with the type
|
||||
``('a -> bool) -> 'a stream -> 'a stream`` that returns the "tail" of
|
||||
a stream after dropping all of the initial values for which the first
|
||||
argument function returns ``false``.
|
||||
|
||||
That is, this function keeps dropping elements of the input stream
|
||||
until it finds one for which the function returns ``true``. This
|
||||
element, and all those that follow it, form the stream that is
|
||||
returned.
|
||||
|
||||
For example, using ``head`` and ``squares`` from our original
|
||||
``streams.ml`` file
|
||||
```
|
||||
head (drop_until (fun v -> v > 35) squares)
|
||||
```
|
||||
should evaluate to ``36``
|
||||
|
||||
|
||||
#### ``map``
|
||||
|
||||
In ``streams.ml`` we defined the functions ``filter`` and ``zip`` to
|
||||
work over lists. You are now asked to define a ``map`` function over
|
||||
steams with the type ``('a -> 'b) -> 'a stream -> 'b stream``. This
|
||||
is the analog to ``map`` over lists.
|
||||
|
||||
|
||||
#### ``squares``, again.
|
||||
|
||||
In the class examples we defined the stream of squares of natural
|
||||
numbers using ``zip`` so that ``squares = zip ( * ) nats nats``.
|
||||
|
||||
We could also define ``squares`` as ``squares_from 1`` using the
|
||||
function defined above.
|
||||
|
||||
Define ``squares_again`` to be equal to ``squares`` but define it
|
||||
using the ``map`` function written above.
|
||||
|
||||
|
||||
#### square roots
|
||||
|
||||
You've previously seen a recursive function and an imperative loop to
|
||||
compute the square root of a floating point number to some specified
|
||||
degree of accuracy.
|
||||
|
||||
We now make use of lazy evaluation to pull apart two aspects of this
|
||||
algorithm
|
||||
|
||||
1. the part the generates a sequence of approximations to
|
||||
the square root of a number, and
|
||||
2. the part that determines when the approximations generated so far
|
||||
are close enough that we can stop generating them
|
||||
|
||||
The **first task** is to define the function ``sqrt_approximations`` with
|
||||
the type ``float -> float stream`` that takes a floating point number
|
||||
and generates the stream of approximations to its square root. This
|
||||
sequence corresponds to the sequence of values that the local variable
|
||||
``guess`` took in a previous implementation of this algorithm.
|
||||
|
||||
For example, ``take 10 (sqrt_approximations 49.0)`` evaluates to
|
||||
```
|
||||
[25.; 13.; 7.; 10.; 8.5; 7.75; 7.375; 7.1875; 7.09375; 7.046875]
|
||||
```
|
||||
|
||||
(Recall that floating point values are approximations or real numbers
|
||||
and thus there may be small round off errors that cause your results
|
||||
to be slightly different from these.)
|
||||
|
||||
The **second task** is to write a function whose purpose is similar to
|
||||
the ``accuracy`` value used in the previous implementations, that is,
|
||||
to determine when to stop generating approximations.
|
||||
|
||||
This function should be named ``epsilon_diff`` with the type ``float
|
||||
-> float stream -> float``. The first argument is a floating point
|
||||
value, perhaps named ``epsilon``. This function pulls values out of the
|
||||
stream until the difference between two successive values in the
|
||||
stream is less than epsilon. It then returns the second of those two
|
||||
values.
|
||||
|
||||
An example below uses a ``stream`` named ``diminishing`` which begins
|
||||
at ``16.0`` and each following value is half of its preceding on.
|
||||
For example, in utop:
|
||||
```
|
||||
# take 10 diminishing ;;
|
||||
- : float list = [16.; 8.; 4.; 2.; 1.; 0.5; 0.25; 0.125; 0.0625; 0.03125]
|
||||
```
|
||||
Define ``diminishing`` in your file.
|
||||
|
||||
We can use ``epsilon_diff`` to as follows:
|
||||
```
|
||||
# epsilon_diff 0.3 diminishing ;;
|
||||
- : float = 0.25
|
||||
```
|
||||
Since the difference between ``0.5`` and ``0.25`` is the first one
|
||||
that is less than ``0.3``, the second of them is returned.
|
||||
|
||||
|
||||
As a **third task**, include the following declarations to compute the
|
||||
square root of ``50.0`` to different degrees of accuracy:
|
||||
```
|
||||
let rough_guess = epsilon_diff 1.0 (sqrt_approximations 50.0)
|
||||
|
||||
let precise_calculation = epsilon_diff 0.00001 (sqrt_approximations 50.0)
|
||||
```
|
||||
|
||||
#### another square root
|
||||
|
||||
The function ``epsilon_diff`` looked at two successive values to
|
||||
determine when to stop traversing a stream.
|
||||
|
||||
We now want to write a square root approximation function that picks
|
||||
the first element out of ``sqrt_approximations`` that is within some
|
||||
threshold. This one looks at the elements of ``sqrt_approximations``
|
||||
separately instead of comparing two of them in determining what value
|
||||
to return.
|
||||
|
||||
This function, named ``sqrt_threshold``, has the type ``float -> float
|
||||
-> float``. The first floating point value is the one we would like
|
||||
to take the square root of, call it ``v``. The second is a threshold
|
||||
value, call it ``t``. We want return the first element, say ``s``, of
|
||||
``sqrt_approximations`` for which the absolute value of ``(s *. s)
|
||||
-. v`` is less than ``t``.
|
||||
|
||||
For full credit this function should make appropriate use of the
|
||||
functions you've already written and those in the ``streams.ml`` file
|
||||
we developed in class.
|
||||
|
||||
This function, at first glance, seems to return more accurate
|
||||
answers than our value of epsilon might suggest. For example,
|
||||
```
|
||||
sqrt_threshold 50.0 3.0
|
||||
```
|
||||
evaluates to ``7.125``.
|
||||
|
||||
Write a comment in your OCaml file just above the definition of
|
||||
``sqrt_threshold`` that explains why this is.
|
||||
|
||||
|
||||
|
306
public-class-repo/Homework/Hwk_06.md
Normal file
306
public-class-repo/Homework/Hwk_06.md
Normal file
|
@ -0,0 +1,306 @@
|
|||
# Homework 6: Search as a Programming Technique
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
**Due:** 11:59pm Monday, April 17
|
||||
|
||||
|
||||
## Introduction
|
||||
|
||||
You will solve two searching problems in this assignment. The first
|
||||
is a tautology checker, the second is a maze runner.
|
||||
|
||||
## Part 1: Tautology Checker
|
||||
|
||||
### Getting Started
|
||||
|
||||
Your task for this homework is to write tautology checker for logical
|
||||
formulas. You should be familiar with the code we wrote for the
|
||||
``subsetsum`` problem in lecture before starting this assignment. *If
|
||||
you don't understand that code, then the work below will be very
|
||||
difficult.*
|
||||
|
||||
|
||||
Below are a few type definitions and functions that you will want to
|
||||
use. As we've done before, place these in a file named ``tautology.ml``
|
||||
in a directory named ``Hwk_06``. This ``Hwk_06`` directory should be
|
||||
in your individual repository.
|
||||
|
||||
|
||||
Our formulas are represented by the following OCaml type:
|
||||
```
|
||||
type formula = And of formula * formula
|
||||
| Or of formula * formula
|
||||
| Not of formula
|
||||
| Prop of string
|
||||
| True
|
||||
| False
|
||||
```
|
||||
|
||||
You will implement the tautology checker in the style that uses
|
||||
exceptions, specifically the style that raises an exception to
|
||||
indicate that the search process should continue.
|
||||
|
||||
Thus we will use the following exception for that.
|
||||
```
|
||||
exception KeepLooking
|
||||
```
|
||||
|
||||
Our tautology checker will search for substitutions for the
|
||||
propositions in the formula for which the formula will evaluate to
|
||||
``false``. The substitutions are similar in structure to the
|
||||
environments that we had in homework 4.
|
||||
|
||||
We'll introduce a name for them, ``subst``, with the following type
|
||||
definition.
|
||||
```
|
||||
type subst = (string * bool) list
|
||||
```
|
||||
|
||||
|
||||
Here is a function for converting substitutions to
|
||||
strings. We'll use this in printing our results.
|
||||
```
|
||||
let show_list show l =
|
||||
let rec sl l =
|
||||
match l with
|
||||
| [] -> ""
|
||||
| [x] -> show x
|
||||
| x::xs -> show x ^ "; " ^ sl xs
|
||||
in "[ " ^ sl l ^ " ]"
|
||||
|
||||
let show_string_bool_pair (s,b) =
|
||||
"(\"" ^ s ^ "\"," ^ (if b then "true" else "false") ^ ")"
|
||||
|
||||
let show_subst = show_list show_string_bool_pair
|
||||
```
|
||||
|
||||
You might also find these helpful
|
||||
```
|
||||
let is_elem v l =
|
||||
List.fold_right (fun x in_rest -> if x = v then true else in_rest) l false
|
||||
|
||||
let rec explode = function
|
||||
| "" -> []
|
||||
| s -> String.get s 0 :: explode (String.sub s 1 ((String.length s) - 1))
|
||||
|
||||
let dedup lst =
|
||||
let f elem to_keep =
|
||||
if is_elem elem to_keep then to_keep else elem::to_keep
|
||||
in List.fold_right f lst []
|
||||
```
|
||||
|
||||
|
||||
### Formula evaluation
|
||||
|
||||
In the process of searching for substitutions for a formula that
|
||||
indicate that the formula is not a tautology, we will want to evaluate
|
||||
a formula for a given substitution.
|
||||
|
||||
This is very much like the expression evaluators that we created for
|
||||
homework 4, except now the environment (or substitution as we've
|
||||
called it here) is a part of the input of the evaluation process.
|
||||
|
||||
This is because our formulas have variables, here called propositions,
|
||||
but they don't have let-clauses that would introduce binding into an
|
||||
environment. So that complete environment/substitution must be passed
|
||||
in.
|
||||
|
||||
Write a function named ``eval`` with the type
|
||||
``formula -> subst -> bool`` that evaluates the input formula using
|
||||
the input substitution to return a value of ``true`` or ``false``.
|
||||
|
||||
In case a proposition occurs in the formula that does not appear in
|
||||
the substitution, just raise an exception. The tests run on your code
|
||||
will only provide proper substitutions (no missing binding) to
|
||||
evaluations.
|
||||
|
||||
For example:
|
||||
```
|
||||
eval (And ( Prop "P", Prop "Q")) [("P",true); ("Q",false)]
|
||||
```
|
||||
will evaluate to ``false``
|
||||
and
|
||||
```
|
||||
eval (And ( Prop "P", Prop "Q")) [("P",true); ("Q",true)]
|
||||
```
|
||||
will evaluate to ``true``.
|
||||
|
||||
|
||||
### "Freevars" for formulas
|
||||
|
||||
The search space for our tautology checker is the set of substitutions
|
||||
for the propositions in a formula. Thus we must determine what
|
||||
variables are used in a formula.
|
||||
|
||||
This is reminiscent of the ``freevars`` function we wrote for
|
||||
expressions in homework 4.
|
||||
|
||||
Write a function ``freevars`` with the type ``formula -> string list``
|
||||
that returns the names of all the propositions in the formula. Be
|
||||
sure to remove duplicates since when we create substitutions based on this
|
||||
list we cannot have more than one binding for the same propositional
|
||||
variable.
|
||||
|
||||
Here are a few evaluations.
|
||||
```
|
||||
freevars (And ( Prop "P", Prop "Q"))
|
||||
```
|
||||
evaluates to ``["P"; "Q"]`` and
|
||||
```
|
||||
freevars (And ( Prop "Q", Prop "P"))
|
||||
```
|
||||
evaluates to ``["Q"; "P"]``. But order doesn't matter.
|
||||
|
||||
Here are a few examples of possible tests that may be run on your
|
||||
solution:
|
||||
```
|
||||
List.exists ( (=) "P" ) (freevars (And ( Prop "P", Prop "Q"))) = true
|
||||
|
||||
List.length (freevars (And ( Prop "P", Or (Prop "Q", Prop "P")))) = 2
|
||||
```
|
||||
|
||||
|
||||
### Tautology Checker
|
||||
|
||||
Given the types and functions defined above we can now get to writing
|
||||
our tautology checker.
|
||||
|
||||
The function will be named ``is_tautology`` and will have the type
|
||||
``formula -> (subst -> subst option) -> subst option``.
|
||||
|
||||
The first argument is, not surprisingly, the formula we wish to check.
|
||||
|
||||
The second argument is a function similar to the ``process_solution``
|
||||
functions we used in the implementations of ``subsetsum``. This
|
||||
function is called when the search process finds a substitution for
|
||||
which the formula evaluates to ``false``. The function gets this
|
||||
substitution as input and can decide to accept it (perhaps by
|
||||
interacting with the user) and in that case returns that substitution
|
||||
in a ``Some`` value.
|
||||
|
||||
If the function does not accept the solution, it should raise the
|
||||
``KeepLooking`` exception.
|
||||
|
||||
We could then use ``is_tautology`` in some interesting ways, just
|
||||
like we did for ``subsetsum`` in lecture. First,
|
||||
we could define the following to return the first substitution that is
|
||||
found:
|
||||
```
|
||||
let is_tautology_first f = is_tautology f (fun s -> Some s)
|
||||
```
|
||||
|
||||
Second, we could define the following to print out all substitutions
|
||||
and always raise the ``KeepLooking`` exception. It will then print
|
||||
all substitutions that make the formula evaluate to ``false`` and the
|
||||
finally return ``None`` as the value of the call to
|
||||
``is_tautology_print_all``.
|
||||
```
|
||||
let is_tautology_print_all f =
|
||||
is_tautology
|
||||
f
|
||||
(fun s -> print_endline (show_subst s);
|
||||
raise KeepLooking)
|
||||
```
|
||||
|
||||
For the formula
|
||||
```
|
||||
Or (Prop "P", Not (Prop "P"))
|
||||
```
|
||||
your tautology checker should find that it is a tautology and never
|
||||
generate a substitution.
|
||||
|
||||
For the formula
|
||||
```
|
||||
Or (Prop "P", Prop "Q")
|
||||
```
|
||||
your tautology checker should find that it is not a tautology and
|
||||
generate (among others) the substitution
|
||||
```
|
||||
[ ("Q",false); ("P",false) ]
|
||||
```
|
||||
or
|
||||
```
|
||||
[ ("P",false); ("Q",false) ]
|
||||
```
|
||||
since the order in which binding appear in the substitution does not
|
||||
matter.
|
||||
|
||||
For the formula
|
||||
```
|
||||
And ( Prop "P", Prop "Q")
|
||||
```
|
||||
your tautology checker should find that it is not a tautology and
|
||||
generate 3 substitutions (if they are all demanded) that make the
|
||||
formula false.
|
||||
|
||||
Try
|
||||
```
|
||||
is_tautology_print_all (And (Prop "P", Prop "Q"))
|
||||
```
|
||||
and make sure you see the proper 3 substitutions.
|
||||
|
||||
|
||||
|
||||
Your functions will also be checked that they conform to the proper
|
||||
style and use exceptions as described in class to implement
|
||||
backtracking search.
|
||||
|
||||
|
||||
|
||||
## Part 2: Maze Runner
|
||||
|
||||
Consider the maze shown below, where "S" marks the start position and
|
||||
"G" marks the two goal positions.
|
||||
|
||||
<img src="http://www-users.cs.umn.edu/~evw/Maze.png" alt="Maze" width ="300px"/>
|
||||
|
||||
Your task is to write a function ``maze`` that returns the first
|
||||
path from an "S" position to one of the "G" positions that is found.
|
||||
|
||||
To keep this computation from happening when we load the file into
|
||||
utop, the function should take ``()`` the unit value as input and
|
||||
return a list of pairs on integer representing a path, wrapped up in
|
||||
an ``option`` type.
|
||||
|
||||
This function will have some things in common with the
|
||||
wolf-goat-cabbage problem that we solved in class, so make sure you
|
||||
understand that before attempting this one.
|
||||
|
||||
|
||||
It is suggested that you write a function ``maze_moves`` that takes a
|
||||
position as input with the type ``int * int`` and then returns a list
|
||||
of positions, with type ``(int * int) list`` that are all the
|
||||
positions that could be moved to, while respecting the boundaries and
|
||||
lines in the maze. For example, one cannot move from position
|
||||
``(3,1)`` to position ``(4,1)``.
|
||||
|
||||
You can implement this with a rather large ``match`` expression that
|
||||
just hard-codes the moves seen in the image above.
|
||||
|
||||
|
||||
For example, your solution may execute the search in an order so that
|
||||
``maze ()`` evaluates to
|
||||
```
|
||||
Some [ (2,3); (1,3); (1,2); (2,2); (3,2); (3,3); (3,4); (4,4); (4,5); (3,5) ]
|
||||
```
|
||||
Or, your ``maze`` function might instead return the path
|
||||
```
|
||||
Some [ (2,3); (1,3); (1,2); (2,2); (3,2); (3,3); (4,3); (5,3); (5,2); (5,1) ]
|
||||
```
|
||||
|
||||
Thus, the type of ``maze`` must be
|
||||
```
|
||||
unit -> (int * int) list option
|
||||
```
|
||||
|
||||
Your maze runner solution should use the same ``KeepLooking``
|
||||
exception to indicate when a deadend in the search has been reached or
|
||||
when some other reason exists to keep looking for solutions.
|
||||
|
||||
Your functions will also be checked that they conform to the proper
|
||||
style and use exceptions as described in class to implement
|
||||
backtracking search.
|
||||
|
||||
|
||||
|
262
public-class-repo/Homework/Hwk_07.md
Normal file
262
public-class-repo/Homework/Hwk_07.md
Normal file
|
@ -0,0 +1,262 @@
|
|||
# Homework 7: Using OCaml Modules
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
**Due:** 26th April 2017, 5:00 PM
|
||||
|
||||
## Introduction
|
||||
|
||||
In class and in Chapter 9 of Real World OCaml we developed various
|
||||
modules for implementing intervals.
|
||||
|
||||
Of particular interest were the means for constructing signatures (the
|
||||
``module type`` declarations), defining modules that implemented a
|
||||
signature (the ``module`` declarations that name a signature) and
|
||||
functors.
|
||||
|
||||
In this assignment you have some freedom in how you organize your code
|
||||
in different files. But you need at least one file, ``hwk_07.ml``,
|
||||
that is placed in a ``Hwk_07`` directory
|
||||
in your individual repository.
|
||||
|
||||
We will use the command
|
||||
```
|
||||
ocamlbuild hwk_07.byte
|
||||
```
|
||||
to compile your program. Since ``ocamlbuild`` will detect dependencies
|
||||
and compile the named programs you can put some modules in different
|
||||
files.
|
||||
|
||||
Since ``ocamlbuild`` is not installed on the CSE labs machines you can't test
|
||||
this. Use ``utop`` instead and ensure that some combination of ``#mod_use`` and ``#use``
|
||||
directives can be used to load your code.
|
||||
|
||||
**Before you start** read these specifications twice. Your first
|
||||
reading will give you an overview of what is required but may leave
|
||||
you with some questions since there are some dependencies between the
|
||||
various components that make it difficult to enumerate all the
|
||||
requirements in a linear fashion. On a second reading you will find
|
||||
answers to these questions.
|
||||
|
||||
|
||||
## Functors and Signatures for Vectors
|
||||
|
||||
We have seen a few examples for implementing intervals and will use
|
||||
what we learned from those to design modules and signatures for
|
||||
operations over vectors. When the size of a vector is 3, it has a
|
||||
simple geometric interpretation in 3 dimensional space, but we will
|
||||
consider vectors of any size.
|
||||
|
||||
Our vectors will be specified by a signature defining vector
|
||||
operations (to be described below) and this signature should keep the
|
||||
type for representing vectors abstract; that is, it is hidden so that
|
||||
users of the vector cannot manipulate the underlying representation
|
||||
directly.
|
||||
|
||||
Furthermore, vectors are to be parameterized by the kind of numeric
|
||||
module that supports some basic arithmetic operations. This module
|
||||
describes the type and its supporting operations that are the elements
|
||||
of a vector. We could have a vector of integers, a vector of floating
|
||||
point numbers, a vector of complex numbers, even a vector of intervals
|
||||
of integers. These "arithmetic" modules must implement the same
|
||||
signature, perhaps called ``Arithmetic_intf`` (but this choice of name
|
||||
is up to you). This signature is similar to the ``Interval_intf`` we
|
||||
defined in lecture.
|
||||
|
||||
Thus, you will need to define a functor for creating vectors. This
|
||||
functor takes a module as input that will support the operations that
|
||||
let it be treated as a number. This is similar to the ``Make_interval``
|
||||
functor in the interval examples.
|
||||
|
||||
This input module should implement an interface that specifies what
|
||||
operations (functions) are needed to treat it as a number so that we
|
||||
can use it as the type of values in a vector. Presumably there will
|
||||
need to be an operation for adding and multiplying these values. We
|
||||
may also need values identifying the identity for addition (that is,
|
||||
what the value zero is for this type) and the identity for
|
||||
multiplication (that is, what the value one is for this type). These
|
||||
are only suggestions as the operations in this signature are really
|
||||
determined by what is required by the operations in the vector
|
||||
functor. This signature is similar to the ``Comparable`` signature
|
||||
used in the interval examples. That ``Comparable`` signature had to
|
||||
provide operations that were used in the functions in the
|
||||
``Make_interval`` functor.
|
||||
|
||||
|
||||
The operations that must be supplied by the module created by the
|
||||
functor are described below.
|
||||
|
||||
+ ``create``. This function take in an integer specifying the size of
|
||||
the vector and an initial value to be copied into all positions in the
|
||||
new vector. The type of this initial value is determined by the
|
||||
module given as input to the functor ``Make_vector``.
|
||||
|
||||
+ ``from_list``. This function takes a list of element values and
|
||||
returns a vector containing those values.
|
||||
|
||||
+ ``to_list``. This function takes a vector and returns a list
|
||||
containing the values in the vector.
|
||||
|
||||
+ ``scalar_add``. This function takes a value and an vector in which
|
||||
the value is the same type as the elements of the vector. It returns
|
||||
a new vector whose values are computed by adding this value to each
|
||||
element of the input vector.
|
||||
|
||||
+ ``scalar_mul`` This function takes a value and an vector in which
|
||||
the value is the same type as the elements of the vector. It returns
|
||||
a new vector whose values are computed by multiplying this value with each
|
||||
element of the input vector.
|
||||
|
||||
+ ``scalar_prod``. This function take two vectors of the same type
|
||||
and computes their scalar product, sometimes called the dot product.
|
||||
This value is returned in an ``option`` type.
|
||||
|
||||
This operation requires that the vectors have the same number of
|
||||
elements. It then multiplies each corresponding pair of values from
|
||||
the two vectors and then adds the up. This multiply and addition
|
||||
operation are the ones defined in the module for the vector element
|
||||
type (that is, the input to the ``Make_vector`` functor).
|
||||
|
||||
If the vectors are not the same size, the value of ``None`` is
|
||||
returned. If they are the same size, then it returns ``Some `` *x*
|
||||
where *x* is the scalar product of the two vectors.
|
||||
|
||||
+ ``to_string`` converts a vector to a string. This string wraps a
|
||||
vector in double angle brackets and prints its size and values. The
|
||||
size and values are separated by a vertical bar ``|`` and the values
|
||||
are separated by commas. Examples can be seen below.
|
||||
|
||||
+ ``size``. This function takes a vector and returns the number of
|
||||
elements contained in it.
|
||||
|
||||
To summarize, the following are needed:
|
||||
1. A signature for the vector modules
|
||||
2. A functor for creating vector modules that implements the signature
|
||||
for vector modules.
|
||||
3. A signature defining the type and operations for the numeric values
|
||||
that will be the elements of the vector. Modules implementing this
|
||||
signature will be the input module to the functor.
|
||||
|
||||
|
||||
|
||||
## Modules and Signatures for Vector Elements and Vectors
|
||||
|
||||
We will create two modules that will be given to the ``Make_vector``
|
||||
functor; these are to be named ``Int_arithmetic`` and
|
||||
``Complex_arithmetic``. The first is for integer values, the second
|
||||
for complex numbers in which the real and imaginary parts are floating
|
||||
point numbers.
|
||||
|
||||
These are similar in spirit to the ``Int_comparable`` modules in
|
||||
``v6/intInterval.ml``.
|
||||
|
||||
Just as ``Int_comparable`` exposed the representation type (there it
|
||||
was ``int``) here the ``Int_arithmetic`` should also expose this
|
||||
``int`` type and the ``Complex_arithmetic`` module should expose the
|
||||
representation type for complex numbers - specifically ``float *
|
||||
float``. This can be seen in the examples below.
|
||||
|
||||
Both of these will implement the signature for numeric values (the
|
||||
signature in #3 in the list above).
|
||||
|
||||
Thus, we can define the following two modules for two different kinds
|
||||
of vectors:
|
||||
```
|
||||
module Int_vector = Make_vector (Int_arithmetic)
|
||||
|
||||
module Complex_vector = Make_vector (Complex_arithmetic)
|
||||
```
|
||||
|
||||
Thus you are required to define the following names of the objects
|
||||
described above:
|
||||
+ ``Make_vector``
|
||||
+ ``Int_arithmetic``
|
||||
+ ``Complex_arithmetic``
|
||||
+ ``Int_vector``
|
||||
+ ``Complex_vector``
|
||||
|
||||
|
||||
## Example evaluations
|
||||
|
||||
Assuming the above declaration of ``Int_vector``
|
||||
has been made consider the following declarations
|
||||
of integer vectors.
|
||||
```
|
||||
let v1 = Int_vector.create 10 1
|
||||
|
||||
let v2 = Int_vector.from_list [1;2;3;4;5]
|
||||
|
||||
let v3 = Int_vector.scalar_add 3 v2
|
||||
|
||||
let v4 = Int_vector.scalar_mul 10 v2
|
||||
|
||||
let i1 = Int_vector.scalar_prod v3 v4
|
||||
|
||||
let l1 = Int_vector.to_list v3
|
||||
|
||||
let i2 = Int_vector.size v4
|
||||
|
||||
let s1 = Int_vector.to_string v1
|
||||
|
||||
let s2 = Int_vector.to_string v2
|
||||
|
||||
let s3 = Int_vector.to_string v3
|
||||
|
||||
let s4 = Int_vector.to_string v4
|
||||
```
|
||||
|
||||
When these declarations are loaded in to utop (assuming the
|
||||
appropriate module declarations have already been loaded) the
|
||||
following is displayed by utop when it reports what has been loaded:
|
||||
```
|
||||
val v1 : Int_vector.t = <abstr>
|
||||
val v2 : Int_vector.t = <abstr>
|
||||
val v3 : Int_vector.t = <abstr>
|
||||
val v4 : Int_vector.t = <abstr>
|
||||
val i1 : int option = Some 1000
|
||||
val l1 : int list = [4; 5; 6; 7; 8]
|
||||
val i2 : int = 5
|
||||
val s1 : string = "<< 10 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 >>"
|
||||
val s2 : string = "<< 5 | 1, 2, 3, 4, 5 >>"
|
||||
val s3 : string = "<< 5 | 4, 5, 6, 7, 8 >>"
|
||||
val s4 : string = "<< 5 | 10, 20, 30, 40, 50 >>"
|
||||
```
|
||||
|
||||
As you can see, the four vectors ``v1``, ``v2``, ``v3``, and ``v4``
|
||||
have abstract values that cannot be displayed by utop.
|
||||
|
||||
Also, we can see how the vectors are converted to strings.
|
||||
|
||||
This should make it clear how the various vector functions operate.
|
||||
|
||||
Similar behavior is observed when complex numbers are used in the
|
||||
vector instead of integers.
|
||||
|
||||
When ``Complex_vector`` has been defined as shown above, consider the
|
||||
following declarations:
|
||||
```
|
||||
let v5 = Complex_vector.from_list [ (1.0, 2.0); (3.0, 4.0); (5.0, 6.0) ]
|
||||
|
||||
let v6 = Complex_vector.scalar_add (5.0, 5.0) v5
|
||||
|
||||
let c1 = Complex_vector.scalar_prod v5 v6
|
||||
|
||||
let s5 = Complex_vector.to_string v5
|
||||
|
||||
let s6 = Complex_vector.to_string v6
|
||||
```
|
||||
When loaded into utop, the following is displayed by utop when it
|
||||
reports what has been loaded:
|
||||
```
|
||||
val v5 : Complex_vector.t = <abstr>
|
||||
val v6 : Complex_vector.t = <abstr>
|
||||
val c1 : Complex_vector.elemType option = Some (-36., 193.)
|
||||
val s5 : string = "<< 3 | (1.+2.i), (3.+4.i), (5.+6.i) >>"
|
||||
val s6 : string = "<< 3 | (6.+7.i), (8.+9.i), (10.+11.i) >>"
|
||||
```
|
||||
(Note that in the type of ``c1`` you see the name that the solution
|
||||
uses for the element type, namely ``elemType``. You may choose another
|
||||
name for this. Assessments will not be based on this particular
|
||||
name.)
|
||||
|
||||
|
44
public-class-repo/Homework/README.md
Normal file
44
public-class-repo/Homework/README.md
Normal file
|
@ -0,0 +1,44 @@
|
|||
# Homeworks
|
||||
|
||||
#### Homework 1, due January 30 at 5:00pm
|
||||
|
||||
Intoduction to OCaml.
|
||||
|
||||
Graded out of 100 points.
|
||||
|
||||
#### Homework 2, due February 17 at 5:00pm
|
||||
|
||||
Working with higher order function
|
||||
|
||||
Graded out of 71 points.
|
||||
|
||||
#### Homework 3, due March 1 at noon.
|
||||
|
||||
Inductive proofs of programs
|
||||
|
||||
Graded out of 70 points.
|
||||
|
||||
#### Homework 4, due March 22 at 5:00pm
|
||||
|
||||
Programs as data.
|
||||
|
||||
Graded out of 100 points.
|
||||
|
||||
#### Homework 5
|
||||
|
||||
Lazy evaluation
|
||||
|
||||
Not yet graded.
|
||||
|
||||
#### Homework 6
|
||||
|
||||
Search
|
||||
|
||||
No yet out.
|
||||
|
||||
#### Homework 7
|
||||
|
||||
Modules
|
||||
|
||||
Not yet out.
|
||||
|
65
public-class-repo/HowTo/Git_SSH_Setup.md
Normal file
65
public-class-repo/HowTo/Git_SSH_Setup.md
Normal file
|
@ -0,0 +1,65 @@
|
|||
# Setup Git to use SSH
|
||||
|
||||
By now you are probably sick of typing in your username and password every time
|
||||
you need to pull or push to the Git repo. You can avoid this by using SSH to
|
||||
connect to GitHub. With HTTPS, you must authenticate with a username and
|
||||
password every time you want to connect to your repo on GitHub. With SSH, you
|
||||
authenticate via file stored on your computer.
|
||||
|
||||
*Note: Please use your internet id (i.e. smith082) in place of
|
||||
"YOUR_INTERNET_ID" throughout this tutorial*
|
||||
|
||||
### Creating an SSH identity
|
||||
|
||||
To use SSH to connect to GitHub, you must first create an SSH identity (key).
|
||||
This is done with the `ssh-keygen` command.
|
||||
|
||||
```shell
|
||||
$ ssh-keygen -t rsa -b 4096 -C "YOUR_INTERNET_ID@umn.edu"
|
||||
```
|
||||
|
||||
The following will show up in your terminal. Press enter when you are asked
|
||||
where to save your SSH key. This will save it in the default location.
|
||||
|
||||
```
|
||||
Generating public/private rsa key pair.
|
||||
Enter file in which to save the key (/home/YOUR_INTERNET_ID/.ssh/id_rsa):
|
||||
Created directory '/home/YOUR_INTERNET_ID/.ssh'.
|
||||
```
|
||||
|
||||
When you are prompted to enter a passphrase, press enter again.
|
||||
|
||||
```
|
||||
Enter passphrase (empty for no passphrase):
|
||||
Enter same passphrase again:
|
||||
```
|
||||
|
||||
You should now have two keys saved in `/home/YOUR_INTERNET_ID/.ssh`.
|
||||
|
||||
`id_rsa` - This is your **private** key and should be kept secret. Do not share
|
||||
this with anyone or put this on the internet.
|
||||
|
||||
`id_rsa.pub` - This is your public key. It is safe to share this, and it can be
|
||||
used to identify you uniquely when logging in.
|
||||
|
||||
### Configuring GitHub to recognize your SSH identity
|
||||
|
||||
Go to https://github.umn.edu/settings/keys and click on *New SSH key*.
|
||||
You should now be prompted to enter in a Title and Key. The title can be
|
||||
whatever you want (e.g. "main"). The Key should be your SSH **public** key. Your
|
||||
public key can be found by with the command below:
|
||||
|
||||
```shell
|
||||
$ cat ~/.ssh/id_rsa.pub
|
||||
```
|
||||
|
||||
Copy the output from this command into the Key section and click *Add SSH key*.
|
||||
|
||||
### Changing Git remote
|
||||
|
||||
To switch over from HTTPS to SSL, cd into your private repo and run this
|
||||
command.
|
||||
|
||||
```shell
|
||||
$ git remote set-url origin git@github.umn.edu:umn-csci-2041S17/repo-YOUR_INTERNET_ID.git
|
||||
```
|
75
public-class-repo/HowTo/How-to-use-OCaml.md
Normal file
75
public-class-repo/HowTo/How-to-use-OCaml.md
Normal file
|
@ -0,0 +1,75 @@
|
|||
# How to use OCaml
|
||||
|
||||
### Install OCaml
|
||||
|
||||
Go back to your account home directory:
|
||||
```
|
||||
% cd
|
||||
```
|
||||
|
||||
Execute the following commands
|
||||
```
|
||||
% module add soft/ocaml
|
||||
% module initadd soft/ocaml
|
||||
```
|
||||
|
||||
The first makes the OCaml tools available for your current shell
|
||||
session, the second makes them available for future shell sessions.
|
||||
|
||||
Execute the following:
|
||||
```
|
||||
% which ocaml
|
||||
```
|
||||
If it does not display the path to the ocaml compiler
|
||||
(it should be **/soft/ocaml-4.03.0/linux_x86_64/bin/ocaml**)
|
||||
then talk to your TA.
|
||||
|
||||
|
||||
# PLEASE FIX BELOW ! ! !
|
||||
|
||||
### Use OCaml
|
||||
|
||||
Go back to the lab_01 directory in your individual repository.
|
||||
Perhaps by the following commands:
|
||||
```
|
||||
% cd
|
||||
% cd csci2041/repo-user0123/Lab_01
|
||||
```
|
||||
|
||||
Start the OCaml interpreter:
|
||||
```
|
||||
% ocaml
|
||||
```
|
||||
|
||||
At the Ocaml prompt (#) enter the following (do type "#use", not just
|
||||
"use"):
|
||||
```
|
||||
# #use "fib.ml" ;;
|
||||
```
|
||||
Note that the prompt is "#" and directives to the interpreter to load
|
||||
files and quit also begin with a "#".
|
||||
|
||||
OCaml will report an error in the program:
|
||||
> File "fib.ml", line 10, characters 30-31:
|
||||
> Error: Unbound value n
|
||||
|
||||
Quit OCaml using the "quit" command as illustrated below:
|
||||
```
|
||||
# #quit ;;
|
||||
```
|
||||
|
||||
Use an editor of your choice (emacs, vim, gedit, etc.) to replace
|
||||
the variable `n` with the correct variable `x`.
|
||||
|
||||
Also, replace the text between dots in the comment with your name if
|
||||
you've not already done so.
|
||||
|
||||
Save the file and repeat the steps above to start OCaml and load the file.
|
||||
|
||||
Now compute the 5th Fibonacci number by typing the following:
|
||||
```
|
||||
# fib 5 ;;
|
||||
```
|
||||
|
||||
There is a bug in this program. It will return `16` instead of the
|
||||
correct answer of `5`. Let's fix that bug now.
|
18
public-class-repo/HowTo/README.md
Normal file
18
public-class-repo/HowTo/README.md
Normal file
|
@ -0,0 +1,18 @@
|
|||
# HowTo ...
|
||||
|
||||
The intention for this directory is to collect various "how-to"
|
||||
documents that are needed during the semester.
|
||||
|
||||
Some of these may be contributed by you, the students in this course.
|
||||
|
||||
Examples include documents on how to use OCaml interpreters, how to
|
||||
install OCaml on different operating systems, how to install OCaml
|
||||
editing modes in different editors. It is hoped that this information
|
||||
can be carried forward to future instances of this course.
|
||||
|
||||
|
||||
+ `How-to-use-OCaml.md` describes how one used OCaml on CSE labs
|
||||
machines.
|
||||
|
||||
+ `Git_SSH_Setup.md` describes how to setup your SSH key to
|
||||
authenticate with github.
|
514
public-class-repo/Labs/Lab_01_Jan_17.md
Normal file
514
public-class-repo/Labs/Lab_01_Jan_17.md
Normal file
|
@ -0,0 +1,514 @@
|
|||
# Lab 1: Getting started with GitHub and OCaml
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
**Due:** Friday, January 20 at 5:00pm. You should be able to complete
|
||||
lab work during the lab. But occasionally some work may not get
|
||||
completed, thus this due date.
|
||||
|
||||
# Introduction
|
||||
|
||||
### Goals of this lab:
|
||||
|
||||
+ In this lab you will set up your University of Minnesota GitHub
|
||||
repository that will be used to turn in your homework assignments for
|
||||
this course.
|
||||
|
||||
+ You will also install the OCaml compilers and associated tools that we
|
||||
will be using in this class.
|
||||
|
||||
+ Finally, you will modify an OCaml program, run it, and turn it in
|
||||
via GitHub.
|
||||
|
||||
|
||||
+ There should be enough computers for each person to have their own.
|
||||
|
||||
+ If you have a laptop, please feel free to use it for this if you want. But keep in mind that your homework is graded on the lab machines and must work there.
|
||||
|
||||
|
||||
### GitHub:
|
||||
|
||||
* The University of Minnesota has its own GitHub installation that we
|
||||
will be using in the course. We **are not** using
|
||||
https://github.com.
|
||||
|
||||
* Git is a software version control system that we will be using in
|
||||
the class. You will turn your work in using GitHub, not Moodle. We
|
||||
will provide feedback on your work using GitHub as well.
|
||||
|
||||
|
||||
### Set up your CSE Labs account if you do not have one
|
||||
|
||||
If you do not yet have a CSE Labs account (and thus your partner had
|
||||
to log into the computer) perhaps because your are a College of
|
||||
Liberal Arts student, then create that account now.
|
||||
|
||||
To do so, go to this web site and fill in the requested information:
|
||||
|
||||
https://wwws.cs.umn.edu/account-management/
|
||||
|
||||
|
||||
# Lab Steps to Complete
|
||||
|
||||
## Working with GitHub and Git
|
||||
|
||||
### Initialize your GitHub account
|
||||
|
||||
+ If you've never logged into https://github.umn.edu, then do so now.
|
||||
Then give your University Internet Id (we'll call this UIID for short)
|
||||
to a lab TA so that they can set up your repository. This is the same
|
||||
as the part of your University email address that comes before the
|
||||
`@umn.edu` part of the address.
|
||||
|
||||
+ Note that this is **not** your student ID number that appears on
|
||||
your student Id card. We will never ask you for that number.
|
||||
|
||||
+ If you've already logged into https://github.umn.edu, then proceed
|
||||
to the next step since your repository should already be set up.
|
||||
|
||||
|
||||
### Verify that your 2041 repository is set up
|
||||
|
||||
+ If your University Internet Id is **user0123** then your repository
|
||||
will be named **repo-user0123**. In the examples and text below,
|
||||
replace **user0123** with your University Internet Id.
|
||||
|
||||
+ Log into https://github.umn.edu and select the **umn-csci-2041S17**
|
||||
organization and click on the repository named **repo-user0123**.
|
||||
|
||||
+ At the URL
|
||||
https://github.umn.edu/umn-csci-2041S17/repo-user0123
|
||||
you should see a list of files in your repository. This will
|
||||
include only a file named **README.md**.
|
||||
|
||||
If this file is not there, speak to a TA in your lab.
|
||||
|
||||
This repository is a database containing the files and the history of
|
||||
all their changes made since they were added to the repository. It is
|
||||
much more than a simple copy of a set of files.
|
||||
|
||||
|
||||
### Setting up Git in your CSE Labs account
|
||||
|
||||
+ Log into your CSE (College of Science and Engineering) account.
|
||||
|
||||
+ Verify Git is installed. Execute the following:
|
||||
|
||||
(But don't type the `%`. That is meant to symbolize the prompt you see in your terminal window. It may be different that the `%` sign. You'll just type `git --version`. Don't type the `%` in any of the other examples below.)
|
||||
```
|
||||
% git --version
|
||||
```
|
||||
|
||||
+ Configure Git.
|
||||
|
||||
You need to tell Git what your name, email address and favorite
|
||||
editor are. Below is the series of commands that you should
|
||||
enter. Be sure to fill in the appropriate details for yourself
|
||||
|
||||
```
|
||||
% git config --global user.name "YOUR NAME HERE"
|
||||
% git config --global user.email "YOUR UMN EMAIL ADDRESS"
|
||||
% git config --global core.editor "nano"
|
||||
```
|
||||
|
||||
If you have a favorite editor (for example `emacs` or `vim`) then you can enter the command to start that editor where you entered `nano` above.
|
||||
|
||||
Note that your name appears between double quotes since it has spaces
|
||||
in it. Your email address doesn't, so it doesn't need to be in
|
||||
quotes. If you would like "emacs -nw" as your editor (emacs such that
|
||||
it doesn't open a new window but opens in the terminal) then you'll
|
||||
want double quotes around that 2 word phrase.
|
||||
|
||||
Check that these are set correctly; execute
|
||||
|
||||
```
|
||||
git config -l
|
||||
```
|
||||
|
||||
|
||||
### Create a space for your Git workspaces
|
||||
|
||||
Create a directory in your CSE account named "csci2041"
|
||||
(You can use some other name, of course, but in the discussion we will assume that you used "csci2041").
|
||||
|
||||
```
|
||||
% mkdir csci2041
|
||||
% cd csci2041
|
||||
```
|
||||
|
||||
In **csci2041** we will put copies of a "public" read-only repository
|
||||
containing files that we want to distribute to you during the semester
|
||||
and also space for your individual repository that only you and the
|
||||
TAs and instructor have access to.
|
||||
|
||||
|
||||
### Clone your individual repository
|
||||
|
||||
The Git "clone" operation makes a copy of a repository and places it
|
||||
in your account. This copy contains the files and also all the
|
||||
history of changes---just like the repository stored on
|
||||
https://github.umn.edu.
|
||||
|
||||
In your **csci2041** directory, execute the following
|
||||
```
|
||||
% git clone http://github.umn.edu/umn-csci-2041S17/repo-user1234.git
|
||||
```
|
||||
|
||||
After entering your UIID credentials this will create the directory
|
||||
called repo-user1234.
|
||||
It will contain a **README.md** file.
|
||||
|
||||
Execute the following:
|
||||
```
|
||||
% cd repo-user1234
|
||||
% ls
|
||||
```
|
||||
|
||||
When you clone your repository Git will create some hidden files
|
||||
stored in the **.git** directory that contain the long name of this
|
||||
repository, so that we won't need to type it anymore.
|
||||
This directory contains the copy of the repository with all the past
|
||||
history of changes to the files and other information. So now there
|
||||
are two copies of your repository.
|
||||
|
||||
These hidden files tell Git where the GitHub central server is so that
|
||||
operations involving the server won't need this long name.
|
||||
|
||||
Execute the following:
|
||||
```
|
||||
% ls -a
|
||||
% ls .git/
|
||||
```
|
||||
|
||||
Modifying these hidden **.git** files by hand, or creating them by
|
||||
copying directories, is an extremely bad idea. It will cause you many
|
||||
headaches with Git. **So don't do it!**
|
||||
|
||||
|
||||
*You only need to do this clone step once to initially install the
|
||||
repository in your account.*
|
||||
|
||||
If you have another computer and want to do some of your homework on
|
||||
that, then you will need to repeat this step for that computer as
|
||||
well.
|
||||
|
||||
|
||||
### Commands that access the repository
|
||||
|
||||
The following command reads these hidden files and will tell you the
|
||||
URL of the central repository, and some other information.
|
||||
|
||||
Execute the following:
|
||||
```
|
||||
% git remote --verbose
|
||||
```
|
||||
|
||||
|
||||
|
||||
A status operation will also tell you if you've made changes to your
|
||||
workspace since the last time you updated it with files from the
|
||||
repository. This is important because we grade your work by getting it
|
||||
out of your repository. If it is in your workspace but not the central
|
||||
GitHub repository we can't see it and it won't be graded.
|
||||
|
||||
Run the following: ``` % git status ``` Since the files in your
|
||||
workspace (see below) and repositories (both local and the one on
|
||||
https://github.umn.edu) are the same, Git tells you as much.
|
||||
|
||||
|
||||
### Working files
|
||||
|
||||
So, if the hidden directory **.git** is another copy of the
|
||||
repository, what are the files in this directory?
|
||||
|
||||
These files are copies of the files that you can edit. You can create
|
||||
new files and delete files that are no longer needed. **But**, we
|
||||
will need to "commit" any changes that we make to these files to the
|
||||
repository, eventually, so that the repository and the "working files"
|
||||
in your account are synchronized.
|
||||
|
||||
Create a `Lab_01` directory and change into it by executing the following:
|
||||
```
|
||||
% mkdir Lab_01
|
||||
% cd Lab_01
|
||||
```
|
||||
|
||||
Using the text editor of your choice, create a file named `fib.ml`
|
||||
in your just-created `Lab_01` directory. Copy the following OCaml
|
||||
code into that file and save it.
|
||||
```
|
||||
(* Author: Eric Van Wyk
|
||||
Modified by: ... replace the text between the dots with your name ... *)
|
||||
|
||||
(* A function computing the Fibonacci sequence: 1, 1, 2, 3, 5, 8, ... *)
|
||||
|
||||
(* There is a bug in the following program. Can you fix it? *)
|
||||
|
||||
let rec fib x =
|
||||
if x < 3 then 1 else fib (n-1) + fib (n-1)
|
||||
```
|
||||
|
||||
Add your name into the comment on the second line of the file.
|
||||
|
||||
Don't worry about the rest of the file, we will learn how to read this
|
||||
OCaml code soon enough.
|
||||
|
||||
### Adding files
|
||||
|
||||
Check the status of your working files and repository by executing the
|
||||
following:
|
||||
```
|
||||
% git status
|
||||
```
|
||||
|
||||
This tells you that there is now an "untracked" file named `fib.ml`
|
||||
and that Git is not tracking changes to this file. To tell Git to do
|
||||
so, we must `add` the file using the following command:
|
||||
```
|
||||
% git add fib.ml
|
||||
```
|
||||
|
||||
Now run `git status` again and see what it says. What is Git telling
|
||||
you here?
|
||||
|
||||
### Committing changes
|
||||
|
||||
Git is now aware of this file and sees that changes have been made
|
||||
that have not be "committed". Only "committed" changes to the file
|
||||
will be pushed up to the central GitHub server (http://github.umn.edu)
|
||||
and thus it is only these that will be graded or assessed.
|
||||
|
||||
To commit the file changes you've made, execute the following
|
||||
```
|
||||
% git commit -a -m "Adding my name to the file"
|
||||
```
|
||||
|
||||
Now go back to your browser and refresh the page showing your
|
||||
repository. Does this file show up there?
|
||||
|
||||
No, it doesn't. The **commit** command adds your changes to your
|
||||
local repository only. We now need to **push** those changes from
|
||||
your local repository up to the one stored on https://github.umn.edu.
|
||||
We will do that next.
|
||||
|
||||
But first, run ``` % git status ``` What is it telling you? Your
|
||||
changes are committed to the local repository but not the "central"
|
||||
one on https://github.umn.edu
|
||||
|
||||
|
||||
### Pushing changes
|
||||
|
||||
Type
|
||||
```
|
||||
% git push
|
||||
```
|
||||
This pushes your changes from your local repository up to the central
|
||||
one.
|
||||
|
||||
Run
|
||||
```
|
||||
% git status
|
||||
```
|
||||
again. It should now tell you that your working copy of the files and
|
||||
both repositories are all synchronized.
|
||||
|
||||
|
||||
In your web browser, check that a file named `Lab_01_Feedback.md` has
|
||||
been added to your repository. You can click on the link to see its
|
||||
contents. These files will typically be generated for your
|
||||
assignments as soon as you push changes to your programs up to GitHub.
|
||||
If the results here are not what you expect then you need to either
|
||||
fix the issues identified with your program, or, talk to a TA or post
|
||||
a question on Moodle to see if there is a problem with the tools that
|
||||
automatically generate these files.
|
||||
|
||||
In this case, these tools will verify that your program is in the
|
||||
right directory, in the right file, but broken and not yet working.
|
||||
Later in the lab you will fix the problems.
|
||||
|
||||
|
||||
### Clone the public repository
|
||||
|
||||
Go back to your **csci2041** directory, by executing the following
|
||||
command:
|
||||
```
|
||||
% cd ../..
|
||||
```
|
||||
|
||||
Now clone the public class repository by executing the following
|
||||
command:
|
||||
```
|
||||
% git clone http://github.umn.edu/umn-csci-2041S17/public-class-repo.git
|
||||
```
|
||||
|
||||
In the directory `Labs` you will see the Markdown file
|
||||
`Lab_01_Jan_17.md` from which this web page is generated.
|
||||
|
||||
When we add new files to the central repository you will be asked to
|
||||
execute the following:
|
||||
```
|
||||
% git pull
|
||||
```
|
||||
This "pulls" changes from the central repository down to your local
|
||||
one and updates the working copy of those files in your account with
|
||||
the changes.
|
||||
|
||||
Try it. It doesn't have any effect, but it doesn't cause any harm
|
||||
either.
|
||||
|
||||
|
||||
## Working with OCaml
|
||||
|
||||
### Install OCaml
|
||||
|
||||
Go back to your account home directory:
|
||||
```
|
||||
% cd
|
||||
```
|
||||
|
||||
Execute the following commands
|
||||
```
|
||||
% module add soft/ocaml
|
||||
% module initadd soft/ocaml
|
||||
```
|
||||
|
||||
The first makes the OCaml tools available for your current shell
|
||||
session, the second makes them available for future shell sessions.
|
||||
|
||||
Execute the following:
|
||||
```
|
||||
% which ocaml
|
||||
```
|
||||
If it does not display the path to the ocaml compiler
|
||||
(it should be **/soft/ocaml-4.03.0/linux_x86_64/bin/ocaml**)
|
||||
then talk to your TA.
|
||||
|
||||
|
||||
|
||||
### Use OCaml
|
||||
|
||||
Go back to the `Lab_01` directory in your individual repository.
|
||||
Perhaps by the following commands:
|
||||
```
|
||||
% cd
|
||||
% cd csci2041/repo-user0123/Lab_01
|
||||
```
|
||||
|
||||
Start the OCaml interpreter:
|
||||
```
|
||||
% ocaml
|
||||
```
|
||||
|
||||
At the Ocaml prompt (#) enter the following (do type "#use", not just
|
||||
"use"):
|
||||
```
|
||||
# #use "fib.ml" ;;
|
||||
```
|
||||
Note that the prompt is "#" and directives to the interpreter to load
|
||||
files and quit also begin with a "#".
|
||||
|
||||
OCaml will report an error in the program:
|
||||
> File "fib.ml", line 10, characters 30-31:
|
||||
> Error: Unbound value n
|
||||
|
||||
Quit OCaml using the "quit" command as illustrated below:
|
||||
```
|
||||
# #quit ;;
|
||||
```
|
||||
|
||||
Use an editor of your choice (emacs, vim, gedit, etc.) to replace
|
||||
the variable `n` with the correct variable `x`.
|
||||
|
||||
Also, replace the text between dots in the comment with your name if
|
||||
you've not already done so.
|
||||
|
||||
Save the file and repeat the steps above to start OCaml and load the file.
|
||||
|
||||
Now compute the 5th Fibonacci number by typing the following:
|
||||
```
|
||||
# fib 5 ;;
|
||||
```
|
||||
|
||||
|
||||
### Fix the sample file
|
||||
|
||||
Using a text editor edit the `fib.ml` file.
|
||||
|
||||
Fix the bug in the definition of the function `fib`. You should just
|
||||
need to replace a `1` with a `2` somewhere and replace the variable
|
||||
`n` with the variable `x`.
|
||||
|
||||
|
||||
There is a bug in this program. It will return `16` instead of the
|
||||
correct answer of `5`. Let's fix that bug now.
|
||||
|
||||
Also, `fib 0` will return `1` instead of `0`. You will need an additional
|
||||
if-then-else expression to check if `x = 0` and then evaluate to `0`. The 'else' branch of this new
|
||||
if-then-else expression will be the if-then-else expression that is there now. It should look something like
|
||||
the following
|
||||
```
|
||||
let rec fib x =
|
||||
if x = 0 then 0 else
|
||||
if x < 3 then 1 else fib (n-1) + fib(n-2)
|
||||
```
|
||||
|
||||
After you've saved the file, test it. Fire up `ocaml` again and see
|
||||
if you get the right answer.
|
||||
|
||||
|
||||
### Commit and push so that the corrected version is up on GitHub.
|
||||
|
||||
Now you need to just turn in your work. First, see what Git says
|
||||
about the status of your files
|
||||
```
|
||||
% git status
|
||||
```
|
||||
It tells you that a file has been modified.
|
||||
You now need to commit your changes and push them up to your central
|
||||
GitHub repository.
|
||||
|
||||
Execute the appropriate `git add` and `git commit` commands and the
|
||||
run `git push`. What is the error message that you get?
|
||||
|
||||
It is telling you that changes have been made to code up on the GitHub
|
||||
server and that you need to "pull" those changes before you can "push"
|
||||
new changes up to the repository.
|
||||
|
||||
Execute the following:
|
||||
```
|
||||
% git pull
|
||||
```
|
||||
|
||||
The above command "should" work and seems to work for many of you. If it doesn't you'll get a message about the need to "merge" the local repository in your account with the repository up on the https://github.umn.edu server.
|
||||
You will be put into an editor window where you could enter a message to document this "merge" operation. There is no need for this comment, so just save the file. Now try `git pull` again. It should tell you that your repository is already up to date.
|
||||
|
||||
You should now see that feedback file in your local directory (just
|
||||
above your `Lab_01` directory. Verify that it is there.
|
||||
|
||||
|
||||
Now do a `git push` to see that your changed code is pushed up to the
|
||||
Github server. Also verify that the feedback file gets updated to
|
||||
indicate that your code is now working properly.
|
||||
|
||||
Verify that this worked, by using your browser to see the changes on
|
||||
https://github.umn.edu.
|
||||
|
||||
|
||||
This concludes Lab 01.
|
||||
|
||||
|
||||
### **Due:** Friday, January 20 at 5:00pm.
|
||||
|
||||
You should be able to complete lab work during the lab. But
|
||||
occasionally some work may not get completed, thus this due date.
|
||||
|
||||
Note that these changes must exist in your repository on
|
||||
https://github.umn.edu. Doing the work, but failing to push those
|
||||
changes to your central repository cannot be assessed.
|
||||
|
||||
After the due date, we will typically run additional tests and the
|
||||
results of this assessment will be put a file named
|
||||
`Lab_01_Assessment.md` in your repository. This file will have your
|
||||
score for the lab. A similar pattern will be repeated for other
|
||||
assignments.
|
||||
|
176
public-class-repo/Labs/Lab_02_Jan_24.md
Normal file
176
public-class-repo/Labs/Lab_02_Jan_24.md
Normal file
|
@ -0,0 +1,176 @@
|
|||
# Lab 2: Introduction to OCaml
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
**Due:** Friday, January 27 at 5:00pm. You should be able to complete
|
||||
lab work during the lab. But occasionally some work may not get
|
||||
completed, thus this due date.
|
||||
|
||||
# Introduction
|
||||
|
||||
### Goals of this lab:
|
||||
|
||||
+ In this lab you will write a few functions in OCaml to begin the
|
||||
process of learning how best to use it.
|
||||
|
||||
+ You will create a file named *lab_02.ml* in a *Lab_02* directory
|
||||
inside your individual class repository.
|
||||
|
||||
Since we use some scripts in grading different aspects of your work
|
||||
it is critical that you name your directories and files exactly as
|
||||
specified.
|
||||
|
||||
|
||||
# Getting started.
|
||||
|
||||
In your individual repository, make a directory named *Lab_02* and
|
||||
change into it:
|
||||
```
|
||||
% mkdir Lab_02
|
||||
% cd Lab_02
|
||||
```
|
||||
|
||||
Create an empty file with the name *lab_02.ml*:
|
||||
```
|
||||
% touch lab_02.ml
|
||||
```
|
||||
|
||||
It is in this file that you will put your solutions to the programming
|
||||
problems below.
|
||||
|
||||
In a separate terminal window, run ``utop`` (the system used in lecture) or ``ocaml``
|
||||
to start the OCaml interpreter. To load the contents of your file type
|
||||
```
|
||||
#use "lab_02.ml" ;;
|
||||
```
|
||||
at the ``#`` prompt. As you edit your file you'll need to do this again each time
|
||||
to load your changes.
|
||||
|
||||
|
||||
# OCaml programming
|
||||
|
||||
Some of the functions that you are asked to solve below are similar to
|
||||
ones we've solved in class. These can be found in ``simple.ml`` in
|
||||
the ``code-examples`` directory of the public repository. Open
|
||||
another tab in your browser and you can see that file
|
||||
[here](https://github.umn.edu/umn-csci-2041S17/public-class-repo/blob/master/SamplePrograms/simple.ml).
|
||||
|
||||
### #1 Circle area, version 1
|
||||
|
||||
Write a function named ``circle_area_v1`` with the type ``float ->
|
||||
float``. This function should take as input the **diameter** (not the
|
||||
radius) of a circle and compute its area.
|
||||
|
||||
For this version, do not use any nested let-expressions or function
|
||||
calls; only use literals like ``3.1415`` and floating point operators
|
||||
such as ``*.``, ``+.``, or ``/.``.
|
||||
|
||||
For example, ``circle_area_v1 2.5`` should evaluate to about ``4.90``.
|
||||
|
||||
### #2 Circle area, version 2
|
||||
|
||||
Now write another version of this function, this time named
|
||||
``circle_area_v2`` with the same type as ``circle_area_v1``.
|
||||
|
||||
This version, however, must use a nested let-expression to define the
|
||||
constant ``pi`` to have the appropriate value. If there are any
|
||||
computations that are duplicated (perhaps computing the radius from
|
||||
the diameter provided as input) use a nested let-expression to give
|
||||
that sub-computation a name and use it accordingly in the computation.
|
||||
|
||||
### #3 Product of a list of elements
|
||||
|
||||
In lecture, we wrote a function to compute the sum of all the values
|
||||
in a list of integers. It had the type ``int list -> int``.
|
||||
|
||||
Write a similar function named ``product`` that computes the product
|
||||
of the values in a list of integers. It will have the same type as
|
||||
the sum function.
|
||||
|
||||
For example, ``product [2; 3; 4]`` should evaluate to ``24``.
|
||||
|
||||
|
||||
### #4 Sum of differences
|
||||
|
||||
For this problem, you are to write a function that again has the type
|
||||
``int list -> int``. It must be called ``sum_diffs`` and it will
|
||||
compute the sum of the differences between all successive pairs of
|
||||
numbers in the list.
|
||||
|
||||
For example, ``sum_diffs [4; 5; 2]`` will evaluate to ``2``.
|
||||
|
||||
You just write a recursive list-processing function for this task,
|
||||
despite the fact that some arithmetic simplification of the
|
||||
computation (in the case above it would be (4-5) + (5-2)) would let us
|
||||
do the computation in just one subtraction operation. Write the function so
|
||||
that it carries out the operation naively and computes the difference between
|
||||
each successive pair of numbers.
|
||||
|
||||
You may assume that this function will only be passed lists of length
|
||||
2 or more, so you don't need patterns to handle, for example, the
|
||||
empty list. Instead, our "base case" will be a pattern that matches
|
||||
a 2-element list, like the following:
|
||||
```
|
||||
| x1::(x2::[]) -> x1 - x2
|
||||
```
|
||||
This pattern has something more complex than a simple name to the
|
||||
right of the ``::`` cons constructor. It has another nested pattern that
|
||||
matches a list of one element. Together, this pattern only
|
||||
matches lists with exactly 2 elements. Note that the parenthesis are
|
||||
not required here; they only make it explicit that the cons
|
||||
constructor is right associative.
|
||||
|
||||
You will also need and another pattern that matches lists of 2 or more
|
||||
elements. This second pattern will need to bind 2 elements of the
|
||||
list some names so that your expression can compute their difference.
|
||||
It will be similar to the one above, but you need to figure out the
|
||||
details.
|
||||
|
||||
|
||||
Don't hesitate to discuss this problem with your fellow students or your TAs.
|
||||
|
||||
|
||||
### #5 2D points and distance between them
|
||||
|
||||
Tuples in OCaml are simple data structures for holding a few values of
|
||||
possibly different types. For example, we might represent points on a
|
||||
plane using two floating point values in a tuple. This type is
|
||||
written ``float * float``.
|
||||
|
||||
A function that returns ``true`` if a point is in the "upper-right" quadrant
|
||||
of a plane might be implemented as follows:
|
||||
```
|
||||
let upper_right (x,y) = x > 0.0 && y > 0.0
|
||||
```
|
||||
This function has the type ``float * float -> bool``.
|
||||
|
||||
Implement a function named ``distance`` with type ``float * float ->
|
||||
float * float -> float`` to compute the distance between two points
|
||||
(each represented as a tuple of 2 ``float`` values).
|
||||
|
||||
You may find the ``sqrt`` function useful in this function.
|
||||
|
||||
|
||||
### #6 Triangle perimeter
|
||||
|
||||
This problem asks you to compute the perimeter of a triangle. For a
|
||||
triangle with 3 corners named p1, p2, and p3, the perimeter is the
|
||||
distance from p1 to p2 plus the distance from p2 to p3 plus the
|
||||
distance from p3 back to p1.
|
||||
|
||||
Implement a function named ``triangle_perimeter`` with type ``float *
|
||||
float -> float * float -> float * float -> float`` to do this.
|
||||
|
||||
|
||||
|
||||
*This concludes lab 02.*
|
||||
|
||||
|
||||
**Due:** Friday, January 27 at 5:00pm. You should be able to
|
||||
complete lab work during the lab. But occasionally some work may not
|
||||
get completed, thus this due date.
|
||||
|
||||
Note that these changes must exist in your repository on
|
||||
github.umn.edu. Doing the work, but failing to push those changes to
|
||||
your central repository cannot be assessed.
|
||||
|
224
public-class-repo/Labs/Lab_03_Jan_31.md
Normal file
224
public-class-repo/Labs/Lab_03_Jan_31.md
Normal file
|
@ -0,0 +1,224 @@
|
|||
# Lab 3: Improving your OCaml code
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
**Due:** Friday, February 3 at 5:00pm. You should be able to complete
|
||||
the discussion portion of this lab work during the lab. But you may
|
||||
need additional time to complete the work on your functions to make
|
||||
sure that they meet the new requirements for writing "good" code.
|
||||
This work needs to be completed by the due date.
|
||||
|
||||
# Introduction
|
||||
|
||||
### Goals of this lab:
|
||||
|
||||
In this lab you will work with 1 or 2 of your classmates to improve
|
||||
the structure and style of your OCaml functions. You will view your
|
||||
classmates solutions to Hwk 01 and allow them to view your solution.
|
||||
|
||||
This sort of sharing is only allowed, obviously, after the due date.
|
||||
|
||||
You will also
|
||||
|
||||
1. remove all ``;;`` since they are not needed in an OCaml file;
|
||||
they only indicate the end of the input when typing a declaration or
|
||||
expression into the interpreter,
|
||||
|
||||
2. remove a clumsy list construction idiom if you are using it (see
|
||||
below), and
|
||||
|
||||
3. improve your functions so that there are no warning
|
||||
messages generated when loading your file into OCaml. (Again, see below).
|
||||
|
||||
|
||||
Details about how to make these changes are provided below.
|
||||
|
||||
|
||||
# Form groups.
|
||||
|
||||
Find 1 or 2 people that you want to work with in lab. Feel free to
|
||||
move around in lab to sit next to the people you are going to work
|
||||
with. Introduce yourselves.
|
||||
|
||||
You will all want to log into the computer on your desk. Then you
|
||||
should log into GitHub and open the page with ``hwk_01.ml`` so that
|
||||
your solution is visible.
|
||||
|
||||
|
||||
# Prepare the files for lab 3
|
||||
|
||||
Create a new directory named ``Lab_03`` and copy your ``hwk_01.ml``
|
||||
file from ``Hwk_01`` into this new directory.
|
||||
|
||||
At the top of this new file, add a comment with your name. Also
|
||||
include the names of the other member or members of your group.
|
||||
|
||||
|
||||
# Determine questions to share.
|
||||
|
||||
As a group, you need to decide which 3 functions you want to share
|
||||
with others in your group, discuss, and then improve your
|
||||
implementation of that function.
|
||||
|
||||
Do not choose the very simple functions ``even``, ``frac_add``, or
|
||||
``frac_mul``.
|
||||
|
||||
|
||||
# Discuss the first function.
|
||||
|
||||
In this part, you will move this selected function to the top of your
|
||||
new ``hwk_01.ml`` file (after the comment with the names) and add a
|
||||
new comment above that describes the changes that you made to the
|
||||
function to address the concerns described below. You must also
|
||||
specify if you are borrowing code from another student and give them
|
||||
proper credit for their work.
|
||||
|
||||
Read this entire section before making any more changes to your new
|
||||
``hwk_01.ml`` file.
|
||||
|
||||
**Each of you needs to explain your solution of the first function to
|
||||
the other 1 or 2 members of your group. Take turns doing this.**
|
||||
|
||||
After (or during) this, discuss the characteristics of the different
|
||||
implementations that you think represent well-written functions. Also
|
||||
discuss the characteristics of your functions that you think that you
|
||||
can improve.
|
||||
|
||||
In doing so, consider the 3 points of improvement listed above.
|
||||
Fixing the first 1 is easy. Read the next two sections to understand
|
||||
how to address the more interesting second and third concerns.
|
||||
Continue your discussion after you've read over these two sections.
|
||||
|
||||
### clumsy list construction
|
||||
|
||||
When constructing a new list, only use the append operator (``@``)
|
||||
when the left argument to ``@`` is a list for which you do not know
|
||||
the size.
|
||||
|
||||
Do not write, for example, ``[ x ] @ my_function rest``.
|
||||
|
||||
Instead use the cons operator (``::``) and write
|
||||
``x :: my_function rest``.
|
||||
|
||||
|
||||
### fixing all warnings
|
||||
|
||||
The automated tests for this lab will reject your code if there are
|
||||
any warning generated for it. Thus you'll need to fix those.
|
||||
|
||||
For example, you may have written a ``head`` function to return the
|
||||
first element of a list as follows:
|
||||
```
|
||||
let head = function
|
||||
| x::xs -> x
|
||||
```
|
||||
|
||||
This would yield a warning message like the following:
|
||||
```
|
||||
File "hwk_01.ml", line 42, characters 4-144:
|
||||
Warning 8: this pattern-matching is not exhaustive.
|
||||
Here is an example of a value that is not matched:
|
||||
[]
|
||||
```
|
||||
telling you that your function doesn't have a clause for the empty
|
||||
list (``[]``).
|
||||
|
||||
The ``head`` function with type ``'a list -> `a`` can only work if it
|
||||
is given a non-empty list. If it is called with an empty list, this
|
||||
is an error in the call of the function, not the function itself.
|
||||
Thus, the author of ``head`` is justified in raising an exception if
|
||||
this input is the empty list. Thus the function should be implemented
|
||||
as follows:
|
||||
```
|
||||
let head = function
|
||||
| x::xs -> x
|
||||
| _ -> raise (Failure "Incorrect input: empty list passed to head")
|
||||
```
|
||||
|
||||
The idea here is that functions need to be explicit about what kind of
|
||||
input they can accept. The type of the function is a good first
|
||||
approximation of this. The type indicates what "type" of data can be
|
||||
passed in, and what "type" of data will be returned. The type system
|
||||
will ensure that these requirement will be satisfied by any call to
|
||||
the function. Any function call with the incorrect types will be
|
||||
rejected by the type checker.
|
||||
|
||||
But this isn't quite enough for functions like ``head``, ``tail``,
|
||||
``max_list``, or ``matrix_transpose``. These function have additional
|
||||
requirements on their inputs that cannot be specified by the type
|
||||
system. For example, that a list is not empty.
|
||||
|
||||
If these cases, it is appropriate to raise an exception with a message
|
||||
stating that the input provided to the function is not correct, or
|
||||
does not meet the specified requirements of the function.
|
||||
|
||||
Note that a function like reverse (``rev``) must work for all possible
|
||||
inputs (that don't have type errors) and thus, for this assignment,
|
||||
there must be no ``raise`` constructs in those functions.
|
||||
|
||||
Part of your revision of each function is to ensure that none of your
|
||||
functions have any warning when loaded into OCaml. For some, this
|
||||
will require raising an exception in the appropriate place.
|
||||
|
||||
Below is a list of when it is allowed to raise exceptions. Please
|
||||
consult this in your work.
|
||||
|
||||
|
||||
# Which functions can raise exceptions?
|
||||
|
||||
+ ``drop``, ``rev``, and ``perimeter`` must work on all (type-correct)
|
||||
input and thus must not have any ``raise`` constructs in their
|
||||
implementation.
|
||||
|
||||
+ ``euclid`` can raise an exception if either of its inputs is not a
|
||||
positive integer.
|
||||
|
||||
+ ``frac_add`` can raise an exception if the denominator is 0. But it
|
||||
is OK if you do not and simply do the computation.
|
||||
|
||||
+ ``frac_simplify`` can raise an exception if the denominator is 0.
|
||||
|
||||
+ ``square_approx`` can raise an exception if the input is not greater
|
||||
than 1.0.
|
||||
|
||||
+ ``max_list`` can raise an exception if the list is empty. This is
|
||||
better than returning ``0`` for the empty list.
|
||||
|
||||
+ ``matrix_scalar_add`` can raise an exception if the input is not a
|
||||
matrix. Your function ``is_matrix`` is now useful here.
|
||||
|
||||
+ The bonus-round problems ``matrix_transpose`` can raise an exception
|
||||
if its input is not
|
||||
|
||||
+ The bonus-round problem ``matrix_multiply`` can raise an exception if
|
||||
either input is not a matrix or if their sizes are such that they
|
||||
cannot be multiplied.
|
||||
|
||||
+ Helper functions such as ``head`` or ``tail`` can raise appropriate
|
||||
exceptions. But most other helper functions probably don't need to.
|
||||
|
||||
|
||||
|
||||
# Repeat this process for the next 2 functions that you have chosen.
|
||||
|
||||
If you run low on time and can only complete 2 functions that is OK.
|
||||
|
||||
|
||||
# What to turn in.
|
||||
|
||||
You need to turn in your new ``hwk_01.ml`` file in the new ``Lab_03``
|
||||
directory via GitHub.
|
||||
|
||||
This file must contain your name and the names of those you worked
|
||||
with.
|
||||
|
||||
For each function that your worked on with your group, you must
|
||||
provide a detailed comment above it explaining the changes that you
|
||||
made and explain how they improve the implementation of your function.
|
||||
You must also indicate where the ideas for the changes came from -
|
||||
that is, who in your group contributed them.
|
||||
|
||||
For the remainder of the functions, use what you learned from these
|
||||
discussions with your classmates to make sure that none of them
|
||||
produce any warnings and raise exceptions with an appropriate message
|
||||
and only in the cases described above.
|
12
public-class-repo/Labs/Lab_04_Feb_07.md
Normal file
12
public-class-repo/Labs/Lab_04_Feb_07.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Lab 4: Higher order functional programming
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
For this lab, you will begin working on Homework 2.
|
||||
|
||||
You can find its specifications on the public class repository in the
|
||||
``Homework`` directory.
|
||||
|
||||
Use this time to read the specifications over carefully and completely
|
||||
and ask your TAs any qusetions that may arise.
|
||||
|
65
public-class-repo/Labs/Lab_05_Feb_14.md
Normal file
65
public-class-repo/Labs/Lab_05_Feb_14.md
Normal file
|
@ -0,0 +1,65 @@
|
|||
# Lab 5: Quiz 1 results, OCaml versions, Hwk 2
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
|
||||
This lab has three components.
|
||||
|
||||
1. return quiz 1, discuss results, ask questions
|
||||
|
||||
2. use the locally installed version of OCaml
|
||||
|
||||
3. run initial tests
|
||||
|
||||
4. remove warnings from your ``hwk_02.ml`` file
|
||||
|
||||
|
||||
|
||||
## Quiz 1
|
||||
|
||||
Your TAs will return your quiz and go over solutions to the problems.
|
||||
We will not dedicate lecture time to the quiz, so be sure to get your
|
||||
questions answered during lab.
|
||||
|
||||
## OCaml versions.
|
||||
|
||||
To make sure we are using the same version of OCaml that you are using
|
||||
for your work, please ensure that you are using version 4.02.3.
|
||||
|
||||
(This check is to be done on your CSE labs account. If you are using
|
||||
your own laptop for your work, make sure you tests on your CSE labs
|
||||
account or verify that the automated feedback is what you expect.)
|
||||
|
||||
Type the following to check the version number:
|
||||
```
|
||||
ocaml -version
|
||||
```
|
||||
|
||||
If you get something else, try
|
||||
```
|
||||
module initrm soft/ocaml
|
||||
```
|
||||
and then try the previous version check.
|
||||
|
||||
If you still are using something other than version 4.02.3 then ask
|
||||
your TA to help you fix the problem.
|
||||
|
||||
|
||||
### The automated tests
|
||||
The automated feedback tests for homework 2 are now turned on. Make a
|
||||
change to your solution and push it to trigger the tests.
|
||||
|
||||
Make sure that the tests are what you expect and that either your
|
||||
solution is passing them all or you understand why it is not.
|
||||
|
||||
|
||||
### No warnings
|
||||
|
||||
In homework 2 the automated tests code that has warnings is not
|
||||
graded. You do need to remove all warning from your code.
|
||||
|
||||
In doing this, you may need to raise exceptions for data that is not
|
||||
expected by one of your functions. Follow the guidelines we used in
|
||||
lab 3 for doing this.
|
||||
|
||||
|
200
public-class-repo/Labs/Lab_06_Feb_21.md
Normal file
200
public-class-repo/Labs/Lab_06_Feb_21.md
Normal file
|
@ -0,0 +1,200 @@
|
|||
#Lab 6: Inductive Data Types
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
**Due:** Friday, the 24th of February, at 5.00PM.
|
||||
|
||||
This lab will focus on tree based inductive data types and on functions surrounding these.
|
||||
|
||||
##PART A:
|
||||
|
||||
For this part of the lab, use the following type for ``tree``:
|
||||
```
|
||||
type 'a tree = Leaf of 'a
|
||||
| Fork of 'a * 'a tree * 'a tree
|
||||
```
|
||||
|
||||
Some examples using this:
|
||||
+ ``let t1 = Leaf 5``
|
||||
+ ``let t2 = Fork (3, Leaf 3, Fork (2, t1, t1))``
|
||||
+ ``let t3 = Fork ("Hello", Leaf "World", Leaf "!")``
|
||||
|
||||
Below are a list of functions that you will need to implement on this:
|
||||
|
||||
#### 1. ``t_size``
|
||||
Given an 'a tree, write a function ``t_size`` to find the size of the tree. This function will be of the type: ``'a tree -> int``.
|
||||
|
||||
Example:
|
||||
``t_size t3`` gives ``int = 3``.
|
||||
|
||||
#### 2. ``t_sum``
|
||||
Given an int tree, write a function ``t_sum`` to find the sum of the values in the tree. The type of the function is: ``int tree -> int``.
|
||||
|
||||
Example:
|
||||
```
|
||||
let t4 = Fork (7, Fork (5, Leaf 1, Leaf 2), Fork (6, Leaf 3, Leaf 4))
|
||||
```
|
||||
``t_sum t4`` gives ``int = 28``.
|
||||
|
||||
#### 3. ``t_charcount``
|
||||
Write a function ``t_charcount`` that takes a string tree as input and count the total number of characters that the values contain. Type of the function is: ``string tree -> int``.
|
||||
Example:
|
||||
```
|
||||
t_charcount t3 gives int = 11.
|
||||
```
|
||||
|
||||
#### 4. ``t_concat``
|
||||
Now, write a function ``t_concat`` that will concatenate together the values of a string tree. Type of this function is: ``string tree -> string``.
|
||||
Example:
|
||||
```
|
||||
t_concat t3 gives string = "HelloWorld!".
|
||||
```
|
||||
|
||||
##PART B:
|
||||
|
||||
In this part, you will introduce options as well into the above tree type and handle those cases.
|
||||
|
||||
An example:
|
||||
```
|
||||
let t5 : string option tree = Fork (Some "a", Leaf (Some "b"), Fork (Some "c", Leaf None, Leaf (Some "d"))).
|
||||
```
|
||||
This is a tree of type ``string option tree``.
|
||||
|
||||
|
||||
Write 4 new functions, similar to the ones above, but that work over trees with ``option`` values in them
|
||||
For example, ``t_opt_size`` should count the number of values in the tree that is under the "Some" constructor.
|
||||
The types are as follows:
|
||||
|
||||
1) ``t_opt_size : 'a option tree -> int``
|
||||
|
||||
Example:
|
||||
```
|
||||
let t7 = (Fork (Some 1, Leaf (Some 2), Fork (Some 3, Leaf None, Leaf None)))
|
||||
t_opt_size t7
|
||||
```
|
||||
gives
|
||||
|
||||
```
|
||||
int = 3
|
||||
```
|
||||
|
||||
|
||||
2) ``t_opt_sum : int option tree -> int``
|
||||
|
||||
Example:
|
||||
``t_opt_sum t7`` gives ``int = 6``.
|
||||
|
||||
|
||||
3) ``t_opt_charcount : string option tree -> int``
|
||||
|
||||
Example:
|
||||
```
|
||||
let t8 = (Fork (Some "a", Leaf (Some "b"), Fork (Some "c", Leaf None, Leaf (Some "d"))))
|
||||
t_opt_charcount t8
|
||||
```
|
||||
gives
|
||||
```
|
||||
int = 4
|
||||
```
|
||||
|
||||
4) ``t_opt_concat : string option tree -> string``
|
||||
|
||||
Example:
|
||||
```
|
||||
t_opt_concat t8
|
||||
```
|
||||
gives
|
||||
```
|
||||
string = "abcd"
|
||||
```
|
||||
|
||||
##PART C:
|
||||
|
||||
In class, function ``tfold`` with type ``('a -> 'b) -> ('a -> 'b -> 'b -> 'b) -> 'a tree -> 'b`` was introduced. Here is the function:
|
||||
```
|
||||
let rec tfold (l:'a -> 'b) (f:'a -> 'b -> 'b -> 'b) (t:'a tree) : 'b =
|
||||
match t with
|
||||
| Leaf v -> l v
|
||||
| Fork (v, t1, t2) -> f v (tfold l f t1) (tfold l f t2)
|
||||
```
|
||||
The next set of questions will require you to write all the questions in PART A and PART B using tfold and without using recursionss.
|
||||
Name and the type are as follows:
|
||||
```
|
||||
1) tf_size : 'a tree -> int
|
||||
|
||||
2) tf_sum : int tree -> int
|
||||
|
||||
3) tf_char_count : string tree -> int
|
||||
|
||||
4) tf_concat : string tree -> string
|
||||
|
||||
5) tf_opt_size : 'a option tree -> int
|
||||
|
||||
6) tf_opt_sum : int option tree -> int
|
||||
|
||||
7) tf_opt_char_count : string option tree -> int
|
||||
|
||||
8) tf_opt_concat : string option tree -> string
|
||||
```
|
||||
|
||||
##PART D:
|
||||
|
||||
This is the final part of this lab. Instead of using the above tree, will we now use a tree of this type:
|
||||
```
|
||||
type 'a btree = Empty
|
||||
| Node of 'a btree * 'a * 'a btree
|
||||
```
|
||||
This is a sorted tree, and will enable us to create empty trees as well as trees with size two.
|
||||
|
||||
Using this tree type, do the following:
|
||||
|
||||
#### ``bt_insert_by``
|
||||
Write a function ``bt_insert_by`` that will take a comparator, an element and a btree as the input, and insert this element into the btree using the comparator to find the correct position. As the tree is sorted, the criteria to insert is as follows:
|
||||
|
||||
1. the values in the left subtree is always less than or equal to the value of the Node.
|
||||
2. the values in the right subtree is always greater that the value of the Node.
|
||||
|
||||
The following is the type:
|
||||
``bt_insert_by : ('a -> 'a -> int) -> 'a -> 'a btree -> 'a btree``
|
||||
Example:
|
||||
```
|
||||
let t6 = Node (Node (Empty, 3, Empty), 4, Node (Empty, 5, Empty))
|
||||
bt_insert_by compare 6 t6
|
||||
```
|
||||
returns
|
||||
```
|
||||
int btree = Node (Node (Empty, 3, Empty), 4, Node (Empty, 5, Node (Empty, 6, Empty)))
|
||||
```
|
||||
|
||||
You can use the comparator found in the Pervasives (Pervasives.compare) module, but, ensure that you understand how it actually works, lest it inserts the element in the incorrect location.
|
||||
|
||||
#### ``bt_elem_by``
|
||||
Like in the homework, write a similar function ``bt_elem_by`` that will now take as inputs a function, an element and a btree, and return true if the element exists in the tree, or, false otherwise. The type of the function is:
|
||||
``bt_elem_by : ('a -> 'b -> bool) -> 'b -> 'a btree -> bool``
|
||||
|
||||
Example:
|
||||
```
|
||||
let t6 = Node (Node (Empty, 3, Empty), 4, Node (Empty, 5, Empty))
|
||||
bt_elem_by (=) 4 t6
|
||||
```
|
||||
returns ``true``
|
||||
|
||||
#### ``bt_to_list``
|
||||
Create a function ``bt_to_list`` that will take as a btree and create a list of all the values in the btree. The type of the function is ``'a btree -> 'a list``.
|
||||
Example: ``bt_to_list t6`` will return
|
||||
``int list = [3; 4; 5]``.
|
||||
|
||||
#### ``btfold``
|
||||
Like ``tfold``, now create a function ``btfold`` of the type ``'b -> ('b -> 'a -> 'b -> 'b) -> 'a btree -> 'b``.
|
||||
|
||||
#### ``btf_elem_by``
|
||||
Write ``btf_elem_by`` so that it has the same behaviour as ``bt_elem_by`` that you wrote above but this one must not be
|
||||
recursive and must instead use ``btfold``.
|
||||
|
||||
|
||||
#### ``btf_to_list``
|
||||
Similarly, write a new function named ``btf_to_list`` that has the same behaviour as your ``bt_to_list`` function that you wrote above. But now use ``btfold`` instead without recursion. Call this function ``btf_to_list``.
|
||||
|
||||
|
||||
#### ``btf_insert_by`` ? ?
|
||||
Finally, write a comment on why will using ``btfold`` for ``bt_insert_by`` might be difficult.
|
35
public-class-repo/Labs/Lab_07_Feb_28.md
Normal file
35
public-class-repo/Labs/Lab_07_Feb_28.md
Normal file
|
@ -0,0 +1,35 @@
|
|||
#Lab 7: Reasoning About Correctness
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
**Due:** This work is due before you leave lab today.
|
||||
|
||||
In lab today your TAs will present you with some sample OCaml
|
||||
functions and also a property that you will be asked to prove a
|
||||
property of the functions.
|
||||
|
||||
You will be given about 10 minutes to work on this problem before the
|
||||
solution is discussed and explained.
|
||||
|
||||
Create a directory called ``Lab_07`` and in the directory create a
|
||||
file named ``lab_07.txt`` that is a text file the contains both the
|
||||
sample functions given to your lab and also the proof of the property
|
||||
that you are asked to prove.
|
||||
|
||||
Your text file must contain well-marked answers to the following
|
||||
questions:
|
||||
|
||||
1. What is the induction principle for the type of data used in the
|
||||
sample functions?
|
||||
2. What is the property that you are asked to prove?
|
||||
3. What is the "base case" that you need to prove?
|
||||
4. What is the "inductive case" that you are asked to prove?
|
||||
5. What is the "inductive hypothesis" that you can use in proving the
|
||||
inductive case?
|
||||
|
||||
These are questions that you may be asked to answer on the quiz on
|
||||
Wednesday.
|
||||
|
||||
|
||||
|
||||
Commit and push this file before you leave lab today.
|
193
public-class-repo/Labs/Lab_08_Mar_07.md
Normal file
193
public-class-repo/Labs/Lab_08_Mar_07.md
Normal file
|
@ -0,0 +1,193 @@
|
|||
Lab 8: Improving your OCaml Code
|
||||
================================
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
**Due:** Friday, March 10 at 5:00pm. You should be able to complete the
|
||||
discussion portion of this lab work during the lab. But you may need additional
|
||||
time to complete the work on your functions to make sure that they meet the new
|
||||
requirements for writing "good" code. This work needs to be completed by the due
|
||||
date.
|
||||
|
||||
## Introduction
|
||||
### Goals of this lab
|
||||
Similar to what you did in Lab 03,
|
||||
in this lab you will work with 1 or 2 of your classmates to improve the structure
|
||||
and style of your OCaml functions. You will view your classmates solutions to
|
||||
Hwk 02 and allow them to view your solution.
|
||||
|
||||
This sort of sharing is only allowed, obviously, after the due date.
|
||||
|
||||
You will also:
|
||||
|
||||
0. Format your code for readability and understanding (see below) .
|
||||
1. Confirm there are no `;;` in your ocaml file. They are only are used when
|
||||
interacting with the interpreter
|
||||
2. Remove all clumsy list construction (see Lab 03).
|
||||
3. Remove all warnings from the file (see Lab 03).
|
||||
|
||||
## Prepare the files for Lab 8
|
||||
Create a new directory named `Lab_08` and copy your `hwk_02.ml` file from
|
||||
`Hwk_02` into this new directory. Keep the filename as `hwk_02.ml`.
|
||||
|
||||
You will all want to log into the computer on your desk. Then you should log
|
||||
into GitHub and open the page with `hwk_02.ml` so that your solution is visible.
|
||||
|
||||
## Code Formatting
|
||||
In this part, you're not going to make any functional improvements to your
|
||||
programs, instead you will be enhancing your code's readability and to try to
|
||||
help your future partners (and TAs) better understand the logic behind your
|
||||
code.
|
||||
|
||||
Code formatting is an important part of writing software. While most languages
|
||||
don't require any special formatting for the function of your software,
|
||||
maintaining a consistent and readable code style can make
|
||||
understanding and reasoning about your software much easier for yourself and
|
||||
your peers. This is true for OCaml and any other language you find yourself
|
||||
working in.
|
||||
|
||||
We highly recommend that you attempt to emulate the style that is recommended
|
||||
by the OCaml community.
|
||||
[The OCaml website has a style guide that can be found here.]
|
||||
(https://ocaml.org/learn/tutorials/guidelines.html) Nearly any questions about
|
||||
style and formatting for OCaml can be answered by this guide. We'd like to see
|
||||
everyone try to use these styles on future assignments.
|
||||
|
||||
The guide has a key point that it makes right at the beginning:
|
||||
|
||||
>**Writing programs law:** A program is written once, modified ten times, and
|
||||
>read 100 times. So simplify its writing, always keep future modifications in
|
||||
>mind, and never jeopardize readability.
|
||||
|
||||
This statement is true in any language. Speaking from experience, as the size of
|
||||
the application you work on increases, this statement gains more and more truth.
|
||||
|
||||
For the purpose of this assignment, we'd like you to make a few modifications to
|
||||
your code to try to improve your partners' ability to read and understand your
|
||||
logic. Here are a couple of guidelines for common constructs that can be found
|
||||
within most OCaml files (reiterated from the above guide):
|
||||
|
||||
`if cond then e1 else e2` statements should be written differently based on the
|
||||
size of `cond`, `e1`, and `e2`. If they are short, then writing them on the same
|
||||
line is fine. As the size of the statements grow, place them on their own lines.
|
||||
Here is an example where both `e1` and `e2` are long:
|
||||
|
||||
```OCaml
|
||||
if cond then
|
||||
e1
|
||||
else
|
||||
e2
|
||||
```
|
||||
|
||||
`match` statements should have the clauses aligned with the beginning of the
|
||||
construct. If the expression to the right of the pattern matching arrrow is
|
||||
too large, cut the line after the arrow.
|
||||
|
||||
```OCaml
|
||||
match lam with
|
||||
| Abs (x, body) ->
|
||||
1 + size_lambda body
|
||||
| App (lam1, lam2) ->
|
||||
size_lambda lam1 + size_lambda lam2
|
||||
| Var v -> v
|
||||
```
|
||||
|
||||
**Naming lambda expressions** is something you have encountered in this
|
||||
assignment. When the body of lambda expression is long (spanning a few lines
|
||||
give the function a name by defining it in a let-expression. Consider this
|
||||
lambda expression:
|
||||
```OCaml
|
||||
List.map
|
||||
(fun x ->
|
||||
blabla
|
||||
blabla
|
||||
blabla)
|
||||
l
|
||||
```
|
||||
|
||||
Rewrite it as a let statement and name the function like this:
|
||||
|
||||
```OCaml
|
||||
let f x =
|
||||
blabla
|
||||
blabla
|
||||
blabla in
|
||||
List.map f l
|
||||
```
|
||||
|
||||
This is much clearer to read, in particular if the name given to the function is
|
||||
meaningful.
|
||||
|
||||
Please make these style changes to the `Lab_08/hwk_02.ml` file, then commit
|
||||
and push them to your repository before continuing. You can also continue to
|
||||
improve your code as your work with your group. Please try to style your code
|
||||
like this on future assignments :)
|
||||
|
||||
## Form Groups
|
||||
Find 1 or 2 people that you want to work with in lab. Feel free to move around
|
||||
to sit next to the people you are going to work with. Introduce
|
||||
yourselves.
|
||||
|
||||
You will all want to log into the computer on your desk. Then you should log
|
||||
into GitHub and open the page with `hwk_02.ml` so that your solution is visible.
|
||||
Please make sure that your formatting changes have been committed and pushed!
|
||||
|
||||
As you start to work on your assignment, make sure to include a comment with
|
||||
the names of your group members! It is important to give credit for your
|
||||
improvements!
|
||||
|
||||
## Determine the Questions to Share
|
||||
As a group, figure out which 3 functions you want to share with each other. You
|
||||
will be sharing, discussing, and improving your implementations.
|
||||
|
||||
Do not choose the either of the two simplest functions from the assignment
|
||||
`length` and `rev`. Treat `is_elem` and `is_elem_by` as one function for the
|
||||
purposes of improvement. Make sure to include at least one of `paradelle` or
|
||||
`convert_to_non_blank_lines_of_word` as one of the functions you discuss.
|
||||
|
||||
## Discuss the First Function
|
||||
In this part, you will add a new comment above the function that describes the
|
||||
changes that you made to the function to address the concerns described below.
|
||||
You must also specify if you are borrowing code from another student and give
|
||||
them proper credit for their work.
|
||||
|
||||
Read this entire section before making any more changes to your new `hwk_02.ml`
|
||||
file.
|
||||
|
||||
**Each of you needs to explain your solution of the first function to the other
|
||||
1 or 2 members of your group. Take turns doing this.**
|
||||
|
||||
After (or during) this, discuss the characteristics of the different
|
||||
implementations that you think represent well-written functions. Also discuss
|
||||
the characteristics of your functions that you think that you can improve.
|
||||
|
||||
In doing so, make sure that the `;;` are removed from the file, there are no
|
||||
clumsy list construction instances, and that there are no warnings raised.
|
||||
Review the Lab 03 description for details on these issues.
|
||||
|
||||
Compare your usages of the functions you wrote in Part 1 (`dedup`, `split_by`,
|
||||
etc) in Part 2 and 3. Did you effectively use these functions in your
|
||||
definitions for `convert_to_non_blank_lines_of_word` and `paradelle`? Did you
|
||||
rewrite some of the functionality of `is_elem` inside of your `split_by`
|
||||
implementation? Discuss with your group members when and where you used your
|
||||
useful functions from Part 1.
|
||||
|
||||
## Repeat this Process for the Next 2 Functions
|
||||
If you run low on time and can only complete two functions that is fine.
|
||||
|
||||
## What to Turn In
|
||||
You need to turn in your new `hwk_02.ml` file in the new `Lab_08` directory via
|
||||
GitHub.
|
||||
|
||||
**This file must contain your name and the names of those you worked with!**
|
||||
|
||||
For each function that your worked on with your group, you must provide a
|
||||
detailed comment above it explaining the changes that you made and explain how
|
||||
they improve the implementation of your function. You must also indicate where
|
||||
the ideas for the changes came from - that is, who in your group contributed
|
||||
them.
|
||||
|
||||
For the remainder of the functions, use what you learned from these discussions
|
||||
with your classmates to make sure that none of them produce any warnings and
|
||||
raise exceptions with an appropriate message. Also, try to format them for
|
||||
readability.
|
||||
|
14
public-class-repo/Labs/Lab_09_Mar_21.md
Normal file
14
public-class-repo/Labs/Lab_09_Mar_21.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Lab 9: Expression evaluation
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
This lab time is dedicated to solving the lingering issues you
|
||||
may have with your Hwk 04 assignment.
|
||||
|
||||
Use this time to discuss any questions you have with the TAs. Also
|
||||
make sure that your code is passing the feedback tests that you expect
|
||||
it to pass - inspect the ``Hwk_04_Feedback.md`` file that is pushed to
|
||||
your repository after any updates and push that you do.
|
||||
|
||||
If you've completed Hwk 4 you need not attend this lab.
|
||||
|
133
public-class-repo/Labs/Lab_10_Mar_28.md
Normal file
133
public-class-repo/Labs/Lab_10_Mar_28.md
Normal file
|
@ -0,0 +1,133 @@
|
|||
# Lab 10: Lazy Evaluation
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
**Due:** Friday, March 31 at 5:00pm. You should be able to complete
|
||||
this work during lab.
|
||||
|
||||
## Lab goals
|
||||
Doing this lab should get you set up to work on the programming
|
||||
portion of Homework 05 as some of the programming tasks in this lab
|
||||
are similar to those in the homework.
|
||||
|
||||
## Getting started.
|
||||
Copy the file ``streams.ml`` from the public class repository into a
|
||||
new directory named ``Lab_10``. Name the copy of this file
|
||||
``lab_10.ml``.
|
||||
|
||||
Add the following functions to the end of that file. But you should
|
||||
clearly mark the parts of this file that you did not write and
|
||||
attribute them to their author (your instructor) and then indicate
|
||||
where your work starts in the file by adding you name and a comment to
|
||||
this effect.
|
||||
|
||||
Read over the contents of this file and test out the various functions
|
||||
by running them so that you understand how these streams work.
|
||||
|
||||
## Streams
|
||||
Below you are asked to define a series of values (some are functional
|
||||
values) that lead to the definition of ``str_105_nats`` of type
|
||||
``string`` so that it prints out as seen in the following interaction
|
||||
in utop:
|
||||
```
|
||||
utop # print_endline str_105_nats ;;
|
||||
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, 36, 37, 38, 39, 40
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50
|
||||
51, 52, 53, 54, 55, 56, 57, 58, 59, 60
|
||||
61, 62, 63, 64, 65, 66, 67, 68, 69, 70
|
||||
71, 72, 73, 74, 75, 76, 77, 78, 79, 80
|
||||
81, 82, 83, 84, 85, 86, 87, 88, 89, 90
|
||||
91, 92, 93, 94, 95, 96, 97, 98, 99, 100
|
||||
101, 102, 103, 104, 105
|
||||
- : unit = ()
|
||||
```
|
||||
|
||||
#### natural numbers as strings
|
||||
|
||||
First define a function ``str_from`` of type ``int -> string
|
||||
stream``. This function has the same behavior as ``from`` defined in
|
||||
``streams.ml`` except that the numbers are converted into strings.
|
||||
|
||||
For example, ``take 5 (str_from 10)`` should evaluate to the string
|
||||
list ``["10"; "11"; "12"; "13"; "14"]``.
|
||||
|
||||
Next, define ``str_nats`` of type ``string stream``. It corresponds
|
||||
to ``nats``.
|
||||
|
||||
The expression ``take 5 str_nats`` should evaluat to the string list
|
||||
``["1"; "2"; "3"; "4"; "5"]``.
|
||||
|
||||
#### a stream of separator strings
|
||||
In the output above, you'll notice that some numbers are separated by
|
||||
a comma and a space and that others are separated by a newline. You
|
||||
now need to define
|
||||
the stream of strings that are these appropriate separator values.
|
||||
|
||||
Write a function ``separators`` with the type
|
||||
``int -> string -> string stream``.
|
||||
|
||||
Let's call the first argument ``n`` and the second one ``sep``.
|
||||
|
||||
This function returns a stream of strings in which the first ``n``
|
||||
elements of the stream are the string ``sep``, and the next one is
|
||||
that string containing a single new line character, that is ("\n").
|
||||
Then there are ``n`` more copies of ``sep`` before another string with
|
||||
the newline character. This pattern repeats indefinitely.
|
||||
|
||||
For example, the expression
|
||||
``take 10 (separators 2 "$$")`` will evaluate to the following string
|
||||
list
|
||||
```
|
||||
["$$"; "$$"; "\n"; "$$"; "$$"; "\n"; "$$"; "$$"; "\n"; "$$"]
|
||||
```
|
||||
|
||||
Keep in mind that the second input to ``take`` is a steam, not a
|
||||
list. Only its output is a list.
|
||||
|
||||
When you look at the result of the test for this function in your
|
||||
Feedback file on GitHub please note that the newline characters do not
|
||||
appear in the sample output that your expression is supposed to match.
|
||||
That output displays the values and the embedded newline characters
|
||||
just create new lines. But Markdown does not treat newlines as
|
||||
paragraph brakes so the strings just appear mashed together in the
|
||||
output. Just make sure your output of this function looks correct.
|
||||
|
||||
|
||||
Next define the value ``ten_per_line`` of type ``string stream`` that
|
||||
can be used in the following functions to help create the output of
|
||||
``str_105_nats`` seen above.
|
||||
|
||||
#### alternate
|
||||
Next, write the function ``alternate`` that has the type
|
||||
```
|
||||
'a stream -> 'a stream -> 'a stream
|
||||
|
||||
```
|
||||
and combines two streams into one by alternating their values. The
|
||||
result of evaluating the expression ``take 10 (alternate nats (from
|
||||
100))`` is the int list
|
||||
```
|
||||
[1; 100; 2; 101; 3; 102; 4; 103; 5; 104]
|
||||
```
|
||||
|
||||
#### the string with 105 natural numbers
|
||||
Finally, define ``str_105_nats`` that as type ``string`` and whose
|
||||
value can be seen above.
|
||||
|
||||
To this you'll need to combine the functions and values you've defined
|
||||
above, perhaps some from ``streams.ml``, and also either
|
||||
``List.fold_left`` or ``List.fold_right`` to fold up some list of
|
||||
strings (that originally came from ``str_nats`` and out of a call to
|
||||
``separators``) into the single string seen above.
|
||||
|
||||
|
||||
Note that the newline characters don't appear in the output in the
|
||||
Feedback file on GitHub for the test for ``str_105_nats`` either.
|
||||
Just make sure that your output looks like the example above
|
||||
and that there are now extra spaces except as part of the
|
||||
"comma and space" separator value passed into your function
|
||||
``separators``.
|
||||
|
155
public-class-repo/Labs/Lab_11_Apr_04.md
Normal file
155
public-class-repo/Labs/Lab_11_Apr_04.md
Normal file
|
@ -0,0 +1,155 @@
|
|||
# Lab 11: Denotational Semantics
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
**Due:** Friday, April 7 at 5:00pm. You should be able to complete
|
||||
this work during lab.
|
||||
|
||||
|
||||
## Lab goals
|
||||
This lab will explore the interpreter that we wrote in lecture and
|
||||
extend it a bit.
|
||||
|
||||
## Getting started.
|
||||
Copy the file ``interpreter.ml`` from either the
|
||||
``SamplePrograms/Sec_01_1:25pm`` or
|
||||
``SamplePrograms/Sec_10_3:35pm`` directory of
|
||||
the public class repository into a
|
||||
new directory named ``Lab_11``. Name the copy of this file
|
||||
``interpreter.ml``.
|
||||
|
||||
## Review
|
||||
Open the file and familiarize your self with the data types and the
|
||||
functions ``eval`` and ``exec``.
|
||||
|
||||
Run ``exec program_2 []``. And enter ``10``. How many times does
|
||||
``sum`` appear in the final state?
|
||||
|
||||
Create a let-binding in your file of the from
|
||||
```
|
||||
let num_sum = ...
|
||||
```
|
||||
where ``...`` is replaced by the number of times that ``sum`` appears
|
||||
in the final state.
|
||||
|
||||
|
||||
## Add and conditional statement -- if-then-else
|
||||
|
||||
Add a new constructor of the following form to ``stmt``:
|
||||
```
|
||||
| IfThenElse expr * stmt * stmt
|
||||
```
|
||||
Then write to clause for this new constructor in the ``match``
|
||||
expression in ``exec``.
|
||||
|
||||
Next, add a modulus operator constructor to ``expr``:
|
||||
```
|
||||
| Mod of expr * expr
|
||||
```
|
||||
Then write the clause for this new constructor in the ``match``
|
||||
expression in ``eval``.
|
||||
|
||||
Hint: in OCaml, ``mod`` is the infix operator for modulus. Try it out
|
||||
in ``utop``.
|
||||
|
||||
## Another program:
|
||||
Construct a new program of type ``stmt`` named ``program_3``. It
|
||||
should correspond to the following comment already in
|
||||
``interpreter.ml``. Note how ``program_1`` and ``program_2`` both
|
||||
have similar comments for them. You need to construct a let-binding
|
||||
for ``program_3`` that corresponds to the program in the comment below:
|
||||
```
|
||||
(* read x;
|
||||
i = 0;
|
||||
sum_evens = 0;
|
||||
sum_odds = 0;
|
||||
while (i < x) {
|
||||
write i;
|
||||
if i mod 2 = 0 then
|
||||
sum_evens = sum_evens + i;
|
||||
else
|
||||
sum_odds = sum_odds + i;
|
||||
i = i + 1
|
||||
}
|
||||
write sum_evens;
|
||||
write sum_odds
|
||||
*)
|
||||
```
|
||||
|
||||
## Test your extended ``exec``
|
||||
|
||||
Run ``exec program_3 []`` and enter ``8`` when prompted to enter a
|
||||
number.
|
||||
|
||||
It should print out the integers from 0 to 7 and the print 12 and then
|
||||
16.
|
||||
|
||||
Run ``exec program_3 []`` and enter ``15`` when prompted.
|
||||
|
||||
Create the following let-bindings in your file:
|
||||
```
|
||||
let val_sum_evens =
|
||||
let val_sum_odds =
|
||||
let num_sum_evens =
|
||||
let num_sum_odds =
|
||||
```
|
||||
+ give ``val_sum_evens`` the value of ``sum_evens`` in the final state
|
||||
+ give ``val_sum_odds`` the value of ``sum_odds`` in the final state
|
||||
+ give ``num_sum_evens`` the number of times ``sum_evens`` appears in
|
||||
the final state
|
||||
+ give ``num_sum_odds`` the number of times ``sum_odds`` appears in
|
||||
the final state
|
||||
|
||||
|
||||
## Create a testable version of program_3
|
||||
Define ``program_3_test`` in your file to be the same as
|
||||
``program_3``, but replace
|
||||
```
|
||||
Read "x"
|
||||
```
|
||||
with
|
||||
```
|
||||
Assign ("x", Value (Int 12))
|
||||
```
|
||||
|
||||
|
||||
The following should evaluate to ``Int 30``
|
||||
```
|
||||
lookup "sum_evens" (exec program_3_test [])
|
||||
```
|
||||
|
||||
This is one of the automated tests.
|
||||
|
||||
## An if-then and a skip statement
|
||||
Add the following constructors to ``stmt``:
|
||||
```
|
||||
| IfThen of expr * stmt
|
||||
| Skip
|
||||
```
|
||||
The first is the if-then statement you should expect. The second is a
|
||||
"skip" statement that does nothing. It is like ``pass`` in Python or
|
||||
a "noop" in assembly language.
|
||||
|
||||
Complete the implementation of ``exec`` to handle these new
|
||||
constructs. You might implement the ``IfThen`` construct based on
|
||||
the observation that executing "if ...cond... then ...stmt..." is the same as
|
||||
executing "if ...cond... then ...stmt... else skip".
|
||||
|
||||
Next, define ``program_4`` to correspond to to the following comment:
|
||||
```
|
||||
(* y = 0;
|
||||
if x mod 2 = 0 then y = y + 2;
|
||||
if x mod 3 = 0 then y = y + 3;
|
||||
if x mod 4 = 0 then y = y + 4;
|
||||
*)
|
||||
```
|
||||
Now try ``exec program_4 [ ("x",Int 4) ]``.
|
||||
|
||||
For example ``lookup "y" (exec program_4 [ ("x",Int 4) ])`` should
|
||||
evaluate to ``Int 6``.
|
||||
|
||||
## Push your work.
|
||||
Now be sure to commit and push your work. Check the feedback file
|
||||
that should be generated each time you push this work.
|
||||
|
||||
|
13
public-class-repo/Labs/Lab_12_Apr_11.md
Normal file
13
public-class-repo/Labs/Lab_12_Apr_11.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Lab 12: Search as a Programming Technique
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
In this lab you will begin working on Hwk_06 - the assignment on Search.
|
||||
You will find the specifications for Hwk_06 in the usual place. You
|
||||
should try to complete at least ``eval`` and ``freevars`` during lab.
|
||||
|
||||
You will also be able to collect your second attempt at Problem 3 on
|
||||
Quiz 3.
|
||||
|
||||
|
||||
|
15
public-class-repo/Labs/Lab_13_Apr_18.md
Normal file
15
public-class-repo/Labs/Lab_13_Apr_18.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Lab 13: Hwk 5 review and starting Hwk 7
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
In this lab your TAs will present solutions to problems from Hwk 5
|
||||
that you want to see. This will be done on the whiteboards in
|
||||
lecture.
|
||||
|
||||
If you have questions about the assessment of your Hwk 5, then ask the
|
||||
TA that graded your work. They should be in your lab. If not, ask
|
||||
another TA, they should also be able to help you.
|
||||
|
||||
In this lab you may also begin working on Hwk_07 - the assignment on
|
||||
modular programming using OCaml modules. You will find the
|
||||
specifications for Hwk_07 in the usual place.
|
10
public-class-repo/Labs/Lab_14_Apr_25.md
Normal file
10
public-class-repo/Labs/Lab_14_Apr_25.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Lab 14: Hwk 7 and Review of Quiz 4 Solutions
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
In this lab your TAs will present solutions to problems on Quiz 4
|
||||
that you can use in understanding your work on that quiz. Please
|
||||
ask questions about these solutions and how the problems
|
||||
were assessed.
|
||||
|
||||
Afterwards, please use the TAs as a resource for working on Homework 7.
|
BIN
public-class-repo/Labs/Lab_15.tar
Normal file
BIN
public-class-repo/Labs/Lab_15.tar
Normal file
Binary file not shown.
240
public-class-repo/Labs/Lab_15_May_02.md
Normal file
240
public-class-repo/Labs/Lab_15_May_02.md
Normal file
|
@ -0,0 +1,240 @@
|
|||
# Lab 15: Parallel Evaluation
|
||||
|
||||
*CSci 2041: Advanced Programming Principles, Spring 2017*
|
||||
|
||||
**Due:** Friday, Mary 5 at 5:00pm. You may be able to complete
|
||||
this work during lab, but it may take a bit more time.
|
||||
|
||||
## Lab goals.
|
||||
In this lab you will get a chance to see how to generate parallel code
|
||||
based on the map and fold constructs we've studied in class.
|
||||
|
||||
This lab was developed by Nathan Ringo, who has been working in my (Eric's) lab
|
||||
and doing some interesting things with parallel programming in Cilk. Thanks Nathan!
|
||||
|
||||
## Getting started.
|
||||
Copy the file ``Lab_15.tar`` from the ``Labs`` directory in the public
|
||||
class repository into your individual repository. This file should be
|
||||
at the top level - next to all the feedback and assessment files.
|
||||
|
||||
Next, type
|
||||
```
|
||||
tar xf Lab_15.tar
|
||||
```
|
||||
and this should create a ``Lab_15`` directory in which you will do
|
||||
your work.
|
||||
|
||||
Next, type
|
||||
```
|
||||
git add Lab_15
|
||||
```
|
||||
Now Git knows about all the files you'll need to turn in. You'll need
|
||||
to commit and push these later, of course.
|
||||
|
||||
|
||||
## Exploring the code.
|
||||
|
||||
You'll notice that there are a lot of files in this directory.
|
||||
|
||||
It is a working compiler for a small functional language. It includes
|
||||
specifications for a scanner and parser. It includes a definition of
|
||||
the source and target language as well as how to do some of the
|
||||
translation.
|
||||
|
||||
#### Examples
|
||||
|
||||
To get a feel for the source language, look at the ``*.src.txt`` files
|
||||
in the ``examples`` directory.
|
||||
|
||||
There you'll find a few programs in the source language. These
|
||||
consist of a sequence of functions (which may be no functions) and a
|
||||
final expression that is evaluated (often calling these functions).
|
||||
|
||||
You don't need to write any more example programs.
|
||||
|
||||
|
||||
#### Run the translator.
|
||||
|
||||
Try running some examples. Return to the ``Lab_15`` directory and
|
||||
type
|
||||
```
|
||||
./build.sh examples/arithmetic.src.txt
|
||||
```
|
||||
You should see OCaml build the translator, display and compile this
|
||||
program and show the result - which should be 7.
|
||||
|
||||
Try it also for ``funcs.src.txt`` and ``mapseq.src.txt``.
|
||||
|
||||
Also, try ``fibseq.src.txt``. Note how long this takes? When you
|
||||
implement parallel map this parallel version in ``fib.src.txt`` should
|
||||
execute faster.
|
||||
|
||||
The parallel map in ``map.src.txt`` and ``fib.src.txt`` and the fold
|
||||
in ``fold.src.txt`` are not yet implemented. So don't run these yet.
|
||||
|
||||
|
||||
#### The source language
|
||||
|
||||
Next, navigate to the ``src`` directory and look at ``common.ml``.
|
||||
|
||||
This file has definition of binary operators that is shared by both
|
||||
the source and target language. It also contains some functions for
|
||||
accessing the environment - but you shouldn't need to use these.
|
||||
|
||||
Next, look in the ``src_lang.ml`` file. This file defines the
|
||||
``Src_lang`` module (as a file-based module).
|
||||
|
||||
Here you see the definition the program syntax, starting with
|
||||
``program`` - indicating that a source language program is a list of
|
||||
functions (``func``) and an expression (``expr``).
|
||||
|
||||
Functions (``func``) consist of a name, then a list of parameters
|
||||
(each parameter has a name and a type) and then the expression that is
|
||||
the body of the function.
|
||||
|
||||
Expressions and types then follow. These should be mostly self
|
||||
explanatory, but few comments are worthwhile.
|
||||
|
||||
+ ``Array`` creates an array from a list of values
|
||||
+ ``Call`` is a function call. Note that functions are just names, as strings.
|
||||
+ ``Fold`` takes just a function name and an expression that should be
|
||||
an array.
|
||||
+ ``Map`` will map the function (again just a name) across the array
|
||||
expression.
|
||||
+ ``MapSeq`` is a sequential version of map. ``Map`` will have to be
|
||||
translated into parallel code.
|
||||
|
||||
The remainder of the file does some type checking of the code. You
|
||||
need not read this.
|
||||
|
||||
#### The target language
|
||||
|
||||
Now take a look at ``tgt_lang.ml`` which defines the target language
|
||||
of this translator. Programs written in the source language (as
|
||||
defined in ``src_lang.md``) are translated into the target language
|
||||
(as defined in ``tgt_lang.md``).
|
||||
|
||||
The target language is similar to the source in that these programs
|
||||
are also a collection of functions followed by an expression.
|
||||
|
||||
(The target language is then translated to C and executed. This was
|
||||
visible when running the ``build.sh`` script.)
|
||||
|
||||
Expressions are similar but there are some interesting additions
|
||||
+ ``ArrayGet`` will access an array (the first ``expr``) at some index
|
||||
(the second ``expr``). Indexing begins at position 0, like in C.
|
||||
+ ``ArraySize`` returns the size of an array.
|
||||
+ ``Block`` lets statements be written as expressions. A ``Block``
|
||||
expression contains a list of statements that are executed. These are
|
||||
followed by an expression. This expression is then evaluated and the
|
||||
value of this expression is returned as the value of the ``Block``
|
||||
expression.
|
||||
+ ``Call`` function calls are the same as before
|
||||
+ ``Spawn`` will spawn the evaluation of an expression. But the
|
||||
expression that a ``Spawn`` contains should be a ``Call`` expression.
|
||||
|
||||
Statements are also part of this target language.
|
||||
+ ``ArraySet`` is an assignment-like statement that sets the value of
|
||||
an array (the first ``expr``) at an index position (the second
|
||||
``expr``) to be a new value (the third ``expr``).
|
||||
+ ``Decl`` creates a new declaration of a variable using it name,
|
||||
type, and initializing value.
|
||||
+ A ``For`` loop declares a new integer index variable (its first
|
||||
``string`` argument) that ranges from the value of the second ``expr``
|
||||
up to 1 LESS THAN the third ``expr``. This lets one write for loops
|
||||
that range over all indices of an array by counting from 0 to the size
|
||||
of the array. The body of the for loop is ``stmt list``.
|
||||
+ ``Sync`` is the Cilk sync statement we discussed in class.
|
||||
+ ``Sleep`` will delay execution and might be useful in writing slow
|
||||
functions that will exhibit speedup when run in parallel. Without
|
||||
this, some functions are so fast that we don't notice any parallel
|
||||
speedup.
|
||||
|
||||
#### The translation
|
||||
|
||||
OK, you should now look at ``translate.ml``. This defines the
|
||||
functions ``translate``, ``translate_expr``, ``translate_func``
|
||||
and a few more.
|
||||
|
||||
##### Some simple cases
|
||||
You need only worry about ``translate_expr`` and the incomplete
|
||||
definition of ``fold_helper``.
|
||||
|
||||
First look over ``translate_expr``. It does some type checking of the
|
||||
source language program and translates it to the target language.
|
||||
|
||||
The first case of the ``match`` translate array expressions. It does
|
||||
this by mapping the translate function over the list of expressions
|
||||
(``arr``) that are the value that go into the array.
|
||||
|
||||
Similarly, translations of ``BinOp`` binary operations like ``Add``
|
||||
and ``Mul`` are simple too.
|
||||
|
||||
Translating Boolean values (``Bool``) and function calls are also
|
||||
simple.
|
||||
|
||||
There are other simple translations later in the file.
|
||||
|
||||
##### Sequential map.
|
||||
|
||||
The first interesting translation is for the sequential version map
|
||||
function. This code does some type checking and then at the end
|
||||
generates the ``Tgt_lang.Block`` construct that is the translation of
|
||||
``MapSeq``. This block declares the output array, followed by the for
|
||||
loop that sequentially walks down the array applying the function over
|
||||
array elements. The final expression is just a reference (``Var
|
||||
"_map_array"``) that is the value returned.
|
||||
|
||||
##### Parallel map.
|
||||
|
||||
The first task you should complete it to implement the parallel
|
||||
version of the map. This is the ``Map`` construct.
|
||||
|
||||
It is suggested that you copy the translation for the sequential map
|
||||
and modify it by adding appropriate ``Spawn`` and ``Sync`` constructs.
|
||||
|
||||
When finished, return to the ``Lab_15`` directory and run
|
||||
```
|
||||
./build.sh examples/map.src.txt
|
||||
```
|
||||
to run the parallel version of ``mapseq.src.txt``
|
||||
|
||||
Note that there is no noticeable speedup since the work to be done is so
|
||||
small.
|
||||
|
||||
But you should see a difference between ``figseq.src.txt`` and the
|
||||
parallel ``fib.src.txt``.
|
||||
|
||||
|
||||
##### The fold construct
|
||||
|
||||
The next interesting translation is for ``Fold`` operations. Here
|
||||
the provided code does some type checking and translates to a function
|
||||
call to the ``fold_helper`` function that is defined (partially) at
|
||||
the top of this file. This is what we discussed in class last week.
|
||||
The ``fold_helper`` function should implement the parallel execution
|
||||
of a fold function.
|
||||
|
||||
There is nothing to do here. Instead you should complete the
|
||||
definition of ``fold_helper``.
|
||||
|
||||
This will require some careful consideration. So think about this
|
||||
before you start programming. Ask yourself
|
||||
|
||||
+ where will the result be stored?
|
||||
|
||||
+ since there is no assignment statement, how can I use ``ArraySet``
|
||||
to store a single value? Hint: create an array of size 1 and store a
|
||||
temporary result in it.
|
||||
|
||||
To get started, an array of size 1 named ``out`` is already
|
||||
declared.
|
||||
|
||||
+ what do the parameter ``start`` and ``end`` represent, exactly?
|
||||
|
||||
what values of ``start`` and ``end`` indicate that the range
|
||||
contains only 1 item?
|
||||
|
||||
|
||||
This part of the lab will be considered as extra credit worth about
|
||||
1/2 of what a lab is worth.
|
81
public-class-repo/Labs/README.md
Normal file
81
public-class-repo/Labs/README.md
Normal file
|
@ -0,0 +1,81 @@
|
|||
# Labs
|
||||
|
||||
#### Lab 1, Jan 17
|
||||
|
||||
Getting started with OCaml and Git.
|
||||
|
||||
Graded out of 100 points.
|
||||
|
||||
#### Lab 2, Jan 24
|
||||
|
||||
Introduction to OCaml.
|
||||
|
||||
Graded out of 65 points.
|
||||
|
||||
#### Lab 3, Jan 31
|
||||
|
||||
Improving your Hwk 01 OCaml code.
|
||||
|
||||
Graded out of 62 points.
|
||||
|
||||
#### Lab 4, Feb 7
|
||||
|
||||
Higher order functional programming, getting started on Hwk 02.
|
||||
|
||||
Not graded.
|
||||
|
||||
#### Lab 5, Feb 14
|
||||
|
||||
Discussion of Quiz 1 results.
|
||||
|
||||
Not graded.
|
||||
|
||||
#### Lab 6, Feb 21
|
||||
|
||||
Inductive data types.
|
||||
|
||||
Graded out of 73 points.
|
||||
|
||||
#### Lab 7, Feb 28
|
||||
|
||||
Reasoning about correctness.
|
||||
|
||||
Not graded.
|
||||
|
||||
#### Lab 8, Mar 7
|
||||
|
||||
Improving your Hwk 02 OCaml code.
|
||||
|
||||
Will be graded, not yet completed.
|
||||
|
||||
#### Lab 9, Mar 21
|
||||
|
||||
Working on expression evaluation, Hwk 4
|
||||
|
||||
Not graded.
|
||||
|
||||
#### Lab 10, Mar 28
|
||||
|
||||
Working with streams in OCaml.
|
||||
|
||||
Will be graded, not yet completed.
|
||||
|
||||
#### Lab 11, Apr 4
|
||||
|
||||
Denotational semantics.
|
||||
|
||||
Will be graded, not yet completed.
|
||||
|
||||
#### Lab 12, Apr 11
|
||||
|
||||
Search
|
||||
|
||||
Will be graded, not yet completed.
|
||||
|
||||
#### Lab 13, Apr 18
|
||||
|
||||
#### Lab 14, Apr 25
|
||||
|
||||
#### Lab 15, May 2
|
||||
|
||||
|
108
public-class-repo/Notes/Sec_01_1:25pm/feb_20.txt
Normal file
108
public-class-repo/Notes/Sec_01_1:25pm/feb_20.txt
Normal file
|
@ -0,0 +1,108 @@
|
|||
let rec sum = function
|
||||
| [] -> 0
|
||||
| x:xs -> x + sum xs
|
||||
|
||||
P(l1, l2): sum (l1 @ l2) = sum l1 + sum l2
|
||||
|
||||
P(l1) : \forall l2 in 'a list .
|
||||
sum (l1 @ l2) = sum l1 + sum l2
|
||||
|
||||
Base case: l1 = []
|
||||
----------
|
||||
|
||||
P([]) :
|
||||
\forall l2 in 'a list . (
|
||||
|
||||
sum ([] @ l2)
|
||||
|
||||
= sum l2, by properties of lists and append
|
||||
|
||||
= 0 + sum l2, by properties of aritmetic
|
||||
|
||||
= sum [] + sum l2, by def of sum
|
||||
|
||||
)
|
||||
|
||||
Inductive case: l1 = h::t
|
||||
---------------
|
||||
show: P(h::t) : \forall l2 in 'a list .
|
||||
sum ((h::t) @ l2) = sum (h::t) + sum l2
|
||||
|
||||
given: P(t) : \forall l2 in 'a list .
|
||||
sum (t @ l2) = sum t + sum l2
|
||||
|
||||
\forall l2 in 'a list . (
|
||||
|
||||
sum ((h::t) @ l2)
|
||||
|
||||
= sum ( h :: (t @ l2 ) ), by properties of lists and append
|
||||
|
||||
= h + sum ( t @ l2 ), by def of sum
|
||||
|
||||
= h + sum t + sum l2, by inductive hypothesis
|
||||
|
||||
= sum (h::t) + sum l2, by def of sum
|
||||
|
||||
)
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
|
||||
let rec reverse l = match l with
|
||||
| [ ] -> [ ]
|
||||
| x::xs -> reverse xs @ [x]
|
||||
|
||||
P(l1, l2): reverse (l1 @ l2) = reverse l2 @ reverse l1
|
||||
|
||||
Induction over l1.
|
||||
|
||||
Base case: l1 = []
|
||||
----------
|
||||
|
||||
reverse ([] @ l2)
|
||||
|
||||
= reverse l2, by properties of append and lists
|
||||
|
||||
= reverse l2 @ [], by properites of empty lists
|
||||
|
||||
= reverse l2 @ reverse [], by def. of reverse
|
||||
|
||||
Inductive case: l1 = h::t
|
||||
-----------
|
||||
given: reverse (t @ l2) = reverse l2 @ reverse t
|
||||
|
||||
reverse (h::t @ l2)
|
||||
|
||||
= reverse (h :: (t @ l2)), by properties of lists and append
|
||||
|
||||
= reverse (t @ l2) @ [h], by def. of reverse
|
||||
|
||||
= reverse l2 @ rerverse t @ [ h ], by ind. hypo.
|
||||
|
||||
= reverse l2 @ reverse (h::t), by def. of reverse
|
||||
|
||||
------------------------------------------------------------
|
||||
|
||||
|
||||
P(e, l): is_elem e (place e l)
|
||||
|
||||
Induction over l
|
||||
|
||||
Base case: l = []
|
||||
|
||||
is_elem e (place e [])
|
||||
|
||||
= is_elem e [e], by def of place
|
||||
|
||||
= (e = e || e > e && is_elem e []), by def of is_elem
|
||||
|
||||
= true, by properties of equality.
|
||||
|
||||
|
||||
Inductive case: l = h::t
|
||||
show: is_elem e (place e (h::t))
|
||||
|
||||
given: is_elem e (place e t)
|
||||
|
||||
... exercise for the reader ....
|
59
public-class-repo/Notes/Sec_01_1:25pm/mar_20.txt
Normal file
59
public-class-repo/Notes/Sec_01_1:25pm/mar_20.txt
Normal file
|
@ -0,0 +1,59 @@
|
|||
|
||||
double x = x + x
|
||||
|
||||
double (fact 10)
|
||||
|
||||
-- eagerly- call by value
|
||||
double (fact 10)
|
||||
double 3628800
|
||||
3628800 + 3628800
|
||||
7257600
|
||||
|
||||
-- call-by-name
|
||||
double (fact 10)
|
||||
(fact 10) + (fact 10)
|
||||
3628800 + (fact 10)
|
||||
3628800 + 3628800
|
||||
7257600
|
||||
|
||||
-- call-by-need , lazy evaluation
|
||||
double (fact 10)
|
||||
x + x where x = fact 10
|
||||
x + x where x = 3628800
|
||||
3628800 + 3628800
|
||||
7257600
|
||||
|
||||
|
||||
|
||||
take 2 (makefrom 4 15)
|
||||
|
||||
Use the following definitions (clearly not OCaml syntax):
|
||||
|
||||
take n [] = []
|
||||
take 0 (x::xs) = []
|
||||
take n (x::xs) = x::take (n-1) xs
|
||||
|
||||
makefrom 0 v = []
|
||||
makefrom n v = v :: makefrom (n-1) (v+1)
|
||||
|
||||
-- call by name --
|
||||
take 2 (makefrom 4 15)
|
||||
= take 2 (15::makefrom (4-1) (15+1))
|
||||
= 15::take (2-1) (makefrom (4-1) (15+1))
|
||||
= 15::take (2-1) (makefrom 3 (15+1))
|
||||
= 15::take (2-1) ((15+1)::makefrom(3-1) ((15+1)+1))
|
||||
= 15::take 1 ((15+1)::makefrom(3-1) ((15+1)+1))
|
||||
= 15::(15+1)::take (1-1) (makefrom(3-1) ((15+1)+1))
|
||||
|
||||
-- call by value --
|
||||
take 2 (makefrom 4 15)
|
||||
= take 2 (15::makefrom (4-1) (15+1))
|
||||
= take 2 (15::makefrom 3 16)
|
||||
= take 2 (15::16::makefrom 2 17)
|
||||
= take 2 (15::16::17::makefrom 1 18)
|
||||
= take 2 (15::!6::17::18::makefrom 0 19)
|
||||
= take 2 (15::16::17::18::[])
|
||||
= 15::take 1 (16::17::18::[])
|
||||
= 15::16::(take 0 17::18::[])
|
||||
= 15::16::[]
|
||||
-- don't skip steps, things like 3+1 need to be evaluated properly
|
7
public-class-repo/Notes/Sec_01_1:25pm/mar_22.txt
Normal file
7
public-class-repo/Notes/Sec_01_1:25pm/mar_22.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
Exercise #3:
|
||||
|
||||
Write a function named cond that has the same behavior as OCaml’s
|
||||
if-then-else construct.
|
||||
|
||||
let cond c t f = if c then t else f
|
114
public-class-repo/Notes/Sec_10_3:35pm/feb_20.txt
Normal file
114
public-class-repo/Notes/Sec_10_3:35pm/feb_20.txt
Normal file
|
@ -0,0 +1,114 @@
|
|||
let rec sum = function
|
||||
| [] -> 0
|
||||
| x:xs -> x + sum xs
|
||||
|
||||
P(l1, l2): sum (l1 @ l2) = sum l1 + sum l2
|
||||
|
||||
P(l1) : \forall l2 in int list . sum (l1 @ l2) = sum l1 + sum l2
|
||||
|
||||
Base case : l1 = []
|
||||
--------------------
|
||||
|
||||
\forall l2 in int list . (
|
||||
|
||||
sum ([] @ l2)
|
||||
|
||||
= sum l2, properties of append and lists
|
||||
|
||||
= 0 + sum l2, properties of addition
|
||||
|
||||
= sum [] + sum l2, by def of sum
|
||||
|
||||
)
|
||||
|
||||
|
||||
Inductive case : l1 = h::t
|
||||
--------------------
|
||||
show: \forall l2 in int list . sum ((h::t) @ l2) = sum (h::t) + sum l2
|
||||
|
||||
given: \forall l2 in int list . sum (t @ l2) = sum t + sum l2
|
||||
|
||||
\forall l2 in int list .
|
||||
|
||||
sum ((h::t) @ l2)
|
||||
|
||||
= sum ( h :: (t @ l2) ), properties of lists and append
|
||||
|
||||
= h + sum ( t @ l2 ), by def. of sum
|
||||
|
||||
= h + sum t + sum l2, by inductive hypothesis
|
||||
|
||||
= sum (h::t) + sum l2, by def. sum
|
||||
|
||||
)
|
||||
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
|
||||
let rec reverse l = match l with
|
||||
| [ ] -> [ ]
|
||||
| x::xs -> reverse xs @ [x]
|
||||
|
||||
|
||||
P(l1, l2): reverse (l1 @ l2) = reverse l2 @ reverse l1
|
||||
|
||||
Induction over l1.
|
||||
|
||||
Base case:
|
||||
----------
|
||||
P([], l2): reverse (l1 @ l2) = reverse l2 @ reverse l1
|
||||
|
||||
reverse ([] @ l2)
|
||||
|
||||
= reverse l2, by properties of append and lists
|
||||
|
||||
= reverse l2 @ [], by properties of append and lists
|
||||
|
||||
= reverse l2 @ reverse [], by def. of reverse
|
||||
|
||||
|
||||
|
||||
Inductive case
|
||||
--------------
|
||||
P( (h::t, l2):
|
||||
|
||||
show: reverse ((h::t) @ l2) = reverse l2 @ reverse (h::t)
|
||||
given: reverse (t @ l2) = reverse l2 @ reverse t
|
||||
|
||||
reverse ((h::t) @ l2)
|
||||
|
||||
= reverse ( h :: ( t @ l2 ) ), by properties of append and lists
|
||||
|
||||
= reverse ( t @ l2 ) @ [h], by def. of reverse
|
||||
|
||||
= reverse l2 @ reverse t @ [h], by inductive hypothesis
|
||||
|
||||
= reverse l2 @ (reverse t @ [h]), by associtativity of append
|
||||
|
||||
= reverse l2 @ reverse (h::t), by def. of reverese
|
||||
|
||||
|
||||
--------------------------------------------------
|
||||
let rec place e l = match l with
|
||||
| [ ] -> [e]
|
||||
| x::xs -> if e < x then e::x::xs
|
||||
else x :: (place e xs)
|
||||
let rec is_elem e l = match l with
|
||||
| [ ] -> false
|
||||
| x::xs -> e = x || (e > x && is_elem e xs)
|
||||
|
||||
|
||||
P(e, l) : is_elem e (place e l)
|
||||
|
||||
Induction over l.
|
||||
|
||||
Base:
|
||||
is_elem e (place e [])
|
||||
= is_elem e [e], by def. of place
|
||||
= e = e || (e > e && is_elem e []), by def is_elem
|
||||
= true, because e = e
|
||||
|
||||
Inductive case:
|
||||
|
||||
... exercise for the reader ...
|
79
public-class-repo/Notes/Sec_10_3:35pm/mar_20.txt
Normal file
79
public-class-repo/Notes/Sec_10_3:35pm/mar_20.txt
Normal file
|
@ -0,0 +1,79 @@
|
|||
|
||||
double x = x + x
|
||||
|
||||
double (fact 10)
|
||||
|
||||
-- eagerly- call by value
|
||||
double (fact 10)
|
||||
double 3628800
|
||||
3628800 + 3628800
|
||||
7257600
|
||||
|
||||
-- call-by-name
|
||||
double (fact 10)
|
||||
(fact 10) + (fact 10)
|
||||
3628800 + (fact 10)
|
||||
3628800 + 3628800
|
||||
7257600
|
||||
|
||||
-- call-by-need , lazy evaluation
|
||||
double (fact 10)
|
||||
x + x where x = fact 10
|
||||
x + x where x = 3628800
|
||||
3628800 + 3628800
|
||||
7257600
|
||||
|
||||
|
||||
|
||||
-- An exercise from class --
|
||||
|
||||
take 2 (makefrom 4 5)
|
||||
|
||||
Use the following definitions (clearly not OCaml syntax):
|
||||
|
||||
take n [] = []
|
||||
take 0 (x::xs) = []
|
||||
take n (x::xs) = x::take (n-1) xs
|
||||
|
||||
makefrom 0 v = []
|
||||
makefrom n v = v :: makefrom (n-1) (v+1)
|
||||
|
||||
-- call-by-need
|
||||
take 2 (makefrom 4 5)
|
||||
= take 2 (5 :: makefrom (4-1) (5+1))
|
||||
= 5 :: take (2-1) (makefrom (4-1) (5+1))
|
||||
= 5 :: take (2-1) (makefrom 3 (5+1))
|
||||
= 5 :: take (2-1) (v :: makefrom (3-1) (v+1)) where v = 5+1
|
||||
= 5 :: take 1 (v :: makefrom (3-1) (v+1)) where v = 5+1
|
||||
= 5 :: v :: take (1-1) (makefrom (3-1) (v+1)) where v = 5+1
|
||||
= 5 :: v :: take (1-1) (makefrom (3-1) (v+1)) where v = 6
|
||||
= 5 :: 6 :: take (1-1) (makefrom (3-1) (6+1))
|
||||
= 5 :: 6 :: take (1-1) (makefrom 2 (6+1))
|
||||
= 5 :: 6 :: take (1-1) (v :: makefrom (2-1) (v+1)) where v = 6+1
|
||||
= 5 :: 6 :: take 0 (v :: makefrom (2-1) (v+1)) where v = 6+1
|
||||
= 5 :: 6 :: []
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- call-by-value
|
||||
take 2 (makefrom 4 5)
|
||||
= take 2 (5 :: makefrom (4-1) (5+1))
|
||||
= take 2 (5 :: makefrom 3 (5+1))
|
||||
= take 2 (5 :: makefrom 3 6)
|
||||
= take 2 (5 :: 6 :: makefrom (3-1) (6+1))
|
||||
= take 2 (5 :: 6 :: makefrom 2 (6+1))
|
||||
= take 2 (5 :: 6 :: makefrom 2 7)
|
||||
= take 2 (5 :: 6 :: 7 :: makefrom (2-1) (7+1))
|
||||
= take 2 (5 :: 6 :: 7 :: makefrom 1 (7+1))
|
||||
= take 2 (5 :: 6 :: 7 :: makefrom 1 8)
|
||||
= take 2 (5 :: 6 :: 7 :: 8 :: makefrom (1-1) (8+1))
|
||||
= take 2 (5 :: 6 :: 7 :: 8 :: makefrom 0 (8+1))
|
||||
= take 2 (5 :: 6 :: 7 :: 8 :: makefrom 0 9)
|
||||
= take 2 (5 :: 6 :: 7 :: 8 :: [])
|
||||
= 5 :: take (2-1) (6 :: 7 :: 8 :: [])
|
||||
= 5 :: take 1 (6 :: 7 :: 8 :: [])
|
||||
= 5 :: 6 :: take (1-1) (7 :: 8 :: [])
|
||||
= 5 :: 6 :: take 0 (7 :: 8 :: [])
|
||||
= 5 :: 6 :: []
|
10
public-class-repo/Notes/Sec_10_3:35pm/mar_22.txt
Normal file
10
public-class-repo/Notes/Sec_10_3:35pm/mar_22.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
Exercise #3:
|
||||
|
||||
Write a function named cond that has the same behavior as OCaml’s
|
||||
if-then-else construct.
|
||||
|
||||
let cond a b c = match a with
|
||||
| True -> b
|
||||
| False -> c
|
||||
|
||||
let cond a b c = if a then b else c
|
2
public-class-repo/README.md
Normal file
2
public-class-repo/README.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
# public-class-repo
|
||||
Public course materials
|
96375
public-class-repo/Resources/Intro-to-OCaml_Hickey.pdf
Normal file
96375
public-class-repo/Resources/Intro-to-OCaml_Hickey.pdf
Normal file
File diff suppressed because it is too large
Load diff
BIN
public-class-repo/Resources/OCaml-For-The-Masses_Minsky.pdf
Normal file
BIN
public-class-repo/Resources/OCaml-For-The-Masses_Minsky.pdf
Normal file
Binary file not shown.
14
public-class-repo/Resources/README.md
Normal file
14
public-class-repo/Resources/README.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
# Resources
|
||||
|
||||
In this directory you will find various electronic resources that will
|
||||
be used in the course.
|
||||
|
||||
#### OCaml
|
||||
|
||||
We will make use of Jason Hickey's draft of a book that was not
|
||||
eventually published. But it is still a rather good resource and it
|
||||
is free. It is in the file `Intro-to-OCaml_Hickey.pdf`.
|
||||
|
||||
The article "OCaml for the Masses" by Yaron Minsky provides a
|
||||
compelling discussion for using languages like OCaml in real world
|
||||
applications where speed and correctness matter.
|
57
public-class-repo/SamplePrograms/Concurrency/fib.cilk
Normal file
57
public-class-repo/SamplePrograms/Concurrency/fib.cilk
Normal file
|
@ -0,0 +1,57 @@
|
|||
static const char *ident __attribute__((__unused__))
|
||||
= "$HeadURL: https://bradley.csail.mit.edu/svn/repos/cilk/5.4.3/examples/fib.cilk $ $LastChangedBy: sukhaj $ $Rev: 517 $ $Date: 2003-10-27 10:05:37 -0500 (Mon, 27 Oct 2003) $";
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994-2003 Massachusetts Institute of Technology
|
||||
* Copyright (c) 2003 Bradley C. Kuszmaul
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cilk-lib.cilkh>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int START_OF_CILK_CODE = 0;
|
||||
|
||||
cilk int fib(int n)
|
||||
{
|
||||
if (n < 2)
|
||||
return (n);
|
||||
else {
|
||||
int x, y;
|
||||
x = spawn fib(n - 1);
|
||||
y = spawn fib(n - 2);
|
||||
sync;
|
||||
return (x + y);
|
||||
}
|
||||
}
|
||||
|
||||
cilk int main(int argc, char *argv[])
|
||||
{
|
||||
int n, result;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: fib [<cilk options>] <n>\n");
|
||||
Cilk_exit(1);
|
||||
}
|
||||
n = atoi(argv[1]);
|
||||
result = spawn fib(n);
|
||||
sync;
|
||||
|
||||
printf("Result: %d\n", result);
|
||||
return 0;
|
||||
}
|
17
public-class-repo/SamplePrograms/Concurrency/prog1.ml
Normal file
17
public-class-repo/SamplePrograms/Concurrency/prog1.ml
Normal file
|
@ -0,0 +1,17 @@
|
|||
(* From
|
||||
|
||||
http://www.cs.cornell.edu/courses/cs3110/2011sp/lectures/lec17-concurrency/concurrency.htm
|
||||
*)
|
||||
|
||||
let prog1 n =
|
||||
let result = ref 0 in
|
||||
let f i =
|
||||
for j = 1 to n do
|
||||
let v = !result in
|
||||
Thread.delay (Random.float 1.);
|
||||
result := v + i;
|
||||
Printf.printf "Value %d\n" !result;
|
||||
flush stdout
|
||||
done in
|
||||
ignore (Thread.create f 1);
|
||||
ignore (Thread.create f 2)
|
21
public-class-repo/SamplePrograms/Concurrency/prog2.ml
Normal file
21
public-class-repo/SamplePrograms/Concurrency/prog2.ml
Normal file
|
@ -0,0 +1,21 @@
|
|||
(* From
|
||||
|
||||
http://www.cs.cornell.edu/courses/cs3110/2011sp/lectures/lec17-concurrency/concurrency.htm
|
||||
*)
|
||||
|
||||
let prog2 n =
|
||||
let result = ref 0 in
|
||||
let m = Mutex.create () in
|
||||
let f i =
|
||||
for j = 1 to n do
|
||||
Mutex.lock m;
|
||||
let v = !result in
|
||||
Thread.delay (Random.float 1.);
|
||||
result := v + i;
|
||||
Printf.printf "Value %d\n" !result;
|
||||
flush stdout;
|
||||
Mutex.unlock m;
|
||||
Thread.delay (Random.float 1.)
|
||||
done in
|
||||
ignore (Thread.create f 1);
|
||||
ignore (Thread.create f 2)
|
200
public-class-repo/SamplePrograms/ElemsOfFP_Reade_Chap_8.ml
Normal file
200
public-class-repo/SamplePrograms/ElemsOfFP_Reade_Chap_8.ml
Normal file
|
@ -0,0 +1,200 @@
|
|||
(* This file contains a translation of the Standard ML functions found
|
||||
in sections 1 and 2 of Chapter 8 of Chris Reade's book Elements of
|
||||
Functional Programming into OCaml.
|
||||
|
||||
Note that these functions, just like those in Reade's book, will
|
||||
not evaluate. They are meant to illustrate concepts of lazy
|
||||
functional programming. Since Standard ML and OCaml use eager
|
||||
evaluation these functions do not work. Thus, these have not
|
||||
been loaded into OCaml and thus may have smaller erros in them.
|
||||
|
||||
This translation is provided only to remove the barrier of
|
||||
translating from Standard ML when reading this chapter.
|
||||
|
||||
Sometimes additional functions or values that are not in Reade's
|
||||
chapter 8 are defined (such as plus with the code from page 268) to
|
||||
help clarify the examples in Reade.
|
||||
*)
|
||||
|
||||
(* from page 266 *)
|
||||
let f x = g (h x x)
|
||||
|
||||
|
||||
let g x = 5
|
||||
let rec h x y = h y x
|
||||
let f x = g (h x x)
|
||||
|
||||
|
||||
|
||||
(* page 267 *)
|
||||
snd (raise (Failure "undefined"), 5)
|
||||
|
||||
|
||||
(* page 268 *)
|
||||
let plus x y = x + y
|
||||
let double x = plus x x
|
||||
|
||||
|
||||
|
||||
(* page 269 *)
|
||||
let f x = E
|
||||
|
||||
|
||||
|
||||
(* page 270 *)
|
||||
let rec f x = f x in f ()
|
||||
|
||||
let tl lst =
|
||||
match lst with
|
||||
| (a::x) -> x
|
||||
| [] -> raise (Failure "tl of [] is undefined")
|
||||
|
||||
|
||||
(* page 271 *)
|
||||
let k5 x = 5
|
||||
let k5pr (x, y) = 5
|
||||
|
||||
|
||||
(* page 272 *)
|
||||
let andf a b =
|
||||
match a with
|
||||
| true -> b
|
||||
| false -> false
|
||||
|
||||
let orf a b =
|
||||
match a with
|
||||
| true -> true
|
||||
| false -> b
|
||||
|
||||
|
||||
(* pate 273 *)
|
||||
let cond c x y =
|
||||
match c with
|
||||
| true -> x
|
||||
| false -> y
|
||||
|
||||
let rec equal_lists l1 l2 = (* called just = in Reade *)
|
||||
match l1, l2 with
|
||||
| [], [] -> true
|
||||
| (a::x), (b::y) -> a = b && equal_lists x y
|
||||
| (a::x), [] -> false
|
||||
| [], (b::y) -> false
|
||||
|
||||
type 'a bintree = Lf of 'a
|
||||
| Nd of 'a bintree * 'a bintree
|
||||
(* Note that Reade used "/\" instead of Nd and thus writes this
|
||||
operator using infix notation instead of prefix notation. Thus,
|
||||
where you read "t1 /\ t2" in Reade, we would write it as "Nd t1
|
||||
t2". (Note that OCaml does support some user-defined infix
|
||||
operators be we are not using that capability here.) *)
|
||||
|
||||
|
||||
|
||||
(* page 274 *)
|
||||
let rec eqleaves t1 t2 = leavesof t1 = leavesof t2
|
||||
and leavesof t =
|
||||
match t with
|
||||
| Lf x -> [x]
|
||||
| Nd (t1, t2) -> leavesof t1 @ leavesof t2
|
||||
|
||||
|
||||
(* page 276 *)
|
||||
let rec exists p lst =
|
||||
match lst with
|
||||
| [] -> false
|
||||
| a::x -> if p a then true else exists p x
|
||||
|
||||
let null l =
|
||||
match l with
|
||||
| [] -> true
|
||||
| _ -> false
|
||||
|
||||
|
||||
let rec accumulate f a lst = (* similar to fold_left *)
|
||||
match lst with
|
||||
| [] -> a
|
||||
| b::x -> accumulate f (f a b) x
|
||||
|
||||
let rec reduce f a lst = (* similar to fold_right *)
|
||||
match lst with
|
||||
| [] -> a
|
||||
| b::x -> f b (reduce f a x)
|
||||
|
||||
let cons h t = h :: t
|
||||
let append x y = reduce cons y x
|
||||
|
||||
|
||||
(* page 277 *)
|
||||
let rec append2 x y = revonto y (rev x)
|
||||
and rev x = revonto [] x
|
||||
and revonto y x = accumulate consonto y x
|
||||
and consonto y a = a :: y
|
||||
|
||||
let rec infbt1 = Nd (Lf 6, infbt1)
|
||||
let rec infbt2 = Nd (Nd (infbt2, Lf 2), Nd (Lf 3, infbt1))
|
||||
|
||||
|
||||
|
||||
(* page 279 *)
|
||||
let rec leftmostleaf t =
|
||||
match t with
|
||||
| Lf x -> x
|
||||
| Nd (left, right) -> leftmostleaf left
|
||||
|
||||
let rec ones = 1 :: ones
|
||||
|
||||
|
||||
(* page 280 *)
|
||||
let rec from n = n :: from (n + 1)
|
||||
let nat = from 1
|
||||
|
||||
let rec zip f lst1 lst2 =
|
||||
match lst1, lst2 with
|
||||
| [], [] -> []
|
||||
| a::x, b::y -> f a b :: zip f x y
|
||||
| _, _ -> raise (Failure "zipping lists of different lengths")
|
||||
|
||||
let rec nat = zip plus ones (0 :: nat)
|
||||
|
||||
|
||||
(* page 281 *)
|
||||
let rec factorials = 1 :: zip
|
||||
|
||||
|
||||
|
||||
(* page 282 *)
|
||||
let rec sieve lst =
|
||||
match lst with
|
||||
| a::x -> a :: sieve (sift a x)
|
||||
|
||||
let primes = sieve (from 2)
|
||||
|
||||
let rec multipleof a b = b mod a = 0
|
||||
and non p = fun x -> not p x
|
||||
and sift a x = filter (non (multipleof a)) x
|
||||
|
||||
|
||||
(* page 283 *)
|
||||
let rec nextfind a b lst =
|
||||
match lst with
|
||||
| c::x -> if c < b then c :: nextfind a b x else
|
||||
if c = b then nextfined a (a + b) x else
|
||||
nextfind a (a + b) (c :: x)
|
||||
let sift a x = netfind a (2 * a) x
|
||||
|
||||
|
||||
(* page 287 *)
|
||||
let rec merge2 lst1 lst2 =
|
||||
match lst1, lst2 with
|
||||
| a::x, b::y -> if a < b then a :: merge2 x (b::y) else
|
||||
if a > b then b :: merge2 (a::x) y else
|
||||
a :: merge2 x y
|
||||
|
||||
let merge3 x y z = merge2 x (merge2 y z)
|
||||
|
||||
let times a b = a * b
|
||||
|
||||
let rec hamming = 1 :: merge3 (map (times 2) hamming)
|
||||
(map (times 3) hamming)
|
||||
(map (times 5) hamming)
|
||||
|
5
public-class-repo/SamplePrograms/Intervals/ReadMe.md
Normal file
5
public-class-repo/SamplePrograms/Intervals/ReadMe.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
These examples using intervals are based on the examples in Chapters 4
|
||||
and 9 of Real World OCaml.
|
||||
|
||||
Some small modifications have been made to explain modules, but they
|
||||
are fundamentally the same as in the Real World OCaml book.
|
36
public-class-repo/SamplePrograms/Intervals/v1/intInterval.ml
Normal file
36
public-class-repo/SamplePrograms/Intervals/v1/intInterval.ml
Normal file
|
@ -0,0 +1,36 @@
|
|||
(* A module for intervals over integers.
|
||||
|
||||
This is not an abstract type, all types are exposed.
|
||||
|
||||
The module is used only to collect the types and values
|
||||
into a single entity.
|
||||
|
||||
This code is based on the Interval examples in Chapter 9 of Real
|
||||
World OCaml by Jason Hickey, Anil Madhavapeddy and Yaron Minsky.
|
||||
*)
|
||||
|
||||
type intInterval = Interval of int * int
|
||||
| Empty
|
||||
|
||||
let is_empty (i:intInterval) : bool =
|
||||
match i with
|
||||
| Empty -> true
|
||||
| Interval _ -> false
|
||||
|
||||
let contains (i:intInterval) (x:int) : bool =
|
||||
match i with
|
||||
| Empty -> false
|
||||
| Interval (l,h) -> l <= x && x <= h
|
||||
|
||||
let intersect (i1:intInterval) (i2:intInterval) : intInterval =
|
||||
match i1, i2 with
|
||||
| Empty, _ | _, Empty -> Empty
|
||||
| Interval (l1, h1), Interval (l2, h2) ->
|
||||
Interval (max l1 l2, min h1 h2)
|
||||
|
||||
let to_string (i:intInterval) : string =
|
||||
match i with
|
||||
| Empty -> "Empty"
|
||||
| Interval (l,h) -> "(" ^ string_of_int l ^ ", " ^ string_of_int h ^ ")"
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
|
||||
let i1 = IntInterval.Interval (3, 4)
|
||||
|
||||
let i2 = IntInterval.Interval (3, 6)
|
||||
|
||||
let () =
|
||||
print_endline ("An interval: " ^ IntInterval.to_string i1) ;
|
||||
|
||||
print_endline ("Another interval: " ^ IntInterval.to_string i2) ;
|
||||
|
||||
print_endline ("Their intresection: " ^
|
||||
IntInterval.to_string (IntInterval.intersect i1 i2)) ;
|
41
public-class-repo/SamplePrograms/Intervals/v2/intInterval.ml
Normal file
41
public-class-repo/SamplePrograms/Intervals/v2/intInterval.ml
Normal file
|
@ -0,0 +1,41 @@
|
|||
(* A module for intervals over integers.
|
||||
|
||||
Here, the type is abstract and hidden from users of the code because
|
||||
the corresponding .mli file does not mention the type 'intInterval'.
|
||||
Thus it is not visible since it is not in the interface for this
|
||||
module.
|
||||
|
||||
This code is based on the Interval examples in Chapter 9 of Real
|
||||
World OCaml by Jason Hickey, Anil Madhavapeddy and Yaron Minsky.
|
||||
*)
|
||||
|
||||
type intInterval = Interval of int * int
|
||||
| Empty
|
||||
|
||||
type t = intInterval
|
||||
|
||||
let create (low: int) (high:int) : t =
|
||||
Interval (low, high)
|
||||
|
||||
let is_empty (i:intInterval) : bool =
|
||||
match i with
|
||||
| Empty -> true
|
||||
| Interval _ -> false
|
||||
|
||||
let contains (i:intInterval) (x:int) : bool =
|
||||
match i with
|
||||
| Empty -> false
|
||||
| Interval (l,h) -> l <= x && x <= h
|
||||
|
||||
let intersect (i1:intInterval) (i2:intInterval) : intInterval =
|
||||
match i1, i2 with
|
||||
| Empty, _ | _, Empty -> Empty
|
||||
| Interval (l1, h1), Interval (l2, h2) ->
|
||||
Interval (max l1 l2, min h1 h2)
|
||||
|
||||
let to_string (i:intInterval) : string =
|
||||
match i with
|
||||
| Empty -> "Empty"
|
||||
| Interval (l,h) -> "(" ^ string_of_int l ^ ", " ^ string_of_int h ^ ")"
|
||||
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
(* An interface file for the intInterval that hides the implementation
|
||||
type.
|
||||
*)
|
||||
|
||||
type t
|
||||
|
||||
val create : int -> int -> t
|
||||
|
||||
val is_empty : t -> bool
|
||||
|
||||
val contains : t -> int -> bool
|
||||
|
||||
val intersect : t -> t -> t
|
||||
|
||||
val to_string : t -> string
|
|
@ -0,0 +1,37 @@
|
|||
(* A sample use of the new IntInterval that hides the
|
||||
implementation type.
|
||||
*)
|
||||
|
||||
(* We now use the 'create' function instead of the hidden "Interval"
|
||||
value constructor. *)
|
||||
|
||||
let i1 = IntInterval.create 3 4
|
||||
|
||||
let i2 = IntInterval.create 3 6
|
||||
|
||||
let () =
|
||||
print_endline ("An interval: " ^ IntInterval.to_string i1) ;
|
||||
print_endline ("Another interval: " ^ IntInterval.to_string i2) ;
|
||||
print_endline ("Their intresection: " ^
|
||||
IntInterval.to_string (IntInterval.intersect i1 i2)) ;
|
||||
|
||||
(* Try uncommenting out these lines to see if we really can't use the
|
||||
Interval value constructor.
|
||||
|
||||
In utop, we (gasp!) can, if we "mod_use" the source file since this
|
||||
ignores the .mli file.
|
||||
|
||||
When using the compiler, via corebuild, then IntInterval.Interval
|
||||
is not defined. It is hidden. We only see the abstract type t.
|
||||
|
||||
The command
|
||||
% corebuild useIntInterval.byte
|
||||
shows the error.
|
||||
*)
|
||||
(*
|
||||
let i3 = IntInterval.Interval (3, 4)
|
||||
|
||||
let i4 = IntInterval.Interval (3, 6)
|
||||
*)
|
||||
|
||||
|
43
public-class-repo/SamplePrograms/Intervals/v3/intervals.ml
Normal file
43
public-class-repo/SamplePrograms/Intervals/v3/intervals.ml
Normal file
|
@ -0,0 +1,43 @@
|
|||
(* Defining the IntInterval module with an explicit signature as a
|
||||
nested module.
|
||||
*)
|
||||
|
||||
|
||||
module IntInterval : sig
|
||||
type t
|
||||
val create : int -> int -> t
|
||||
val is_empty : t -> bool
|
||||
val contains : t -> int -> bool
|
||||
val intersect : t -> t -> t
|
||||
val to_string : t -> string
|
||||
end = struct
|
||||
type intInterval = Interval of int * int
|
||||
| Empty
|
||||
|
||||
type t = intInterval
|
||||
|
||||
let create (low: int) (high:int) : t =
|
||||
Interval (low, high)
|
||||
|
||||
let is_empty (i:intInterval) : bool =
|
||||
match i with
|
||||
| Empty -> true
|
||||
| Interval _ -> false
|
||||
|
||||
let contains (i:intInterval) (x:int) : bool =
|
||||
match i with
|
||||
| Empty -> false
|
||||
| Interval (l,h) -> l <= x && x <= h
|
||||
|
||||
let intersect (i1:intInterval) (i2:intInterval) : intInterval =
|
||||
match i1, i2 with
|
||||
| Empty, _ | _, Empty -> Empty
|
||||
| Interval (l1, h1), Interval (l2, h2) ->
|
||||
Interval (max l1 l2, min h1 h2)
|
||||
|
||||
let to_string (i:intInterval) : string =
|
||||
match i with
|
||||
| Empty -> "Empty"
|
||||
| Interval (l,h) -> "(" ^ string_of_int l ^ ", " ^ string_of_int h ^ ")"
|
||||
end
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
(* A sample use of the new IntInterval that hides the
|
||||
implementation type.
|
||||
|
||||
To compile:
|
||||
% corebuild useIntInterval.byte
|
||||
*)
|
||||
|
||||
(* This 'open' makes visible all the names declared at the top level
|
||||
of the Intervals modules, which is the contents of the intervals.ml
|
||||
file.
|
||||
*)
|
||||
open Intervals
|
||||
|
||||
let i1 = IntInterval.create 3 4
|
||||
|
||||
let i2 = IntInterval.create 3 6
|
||||
|
||||
let () =
|
||||
print_endline ("An interval: " ^ IntInterval.to_string i1) ;
|
||||
print_endline ("Another interval: " ^ IntInterval.to_string i2) ;
|
||||
print_endline ("Their intresection: " ^
|
||||
IntInterval.to_string (IntInterval.intersect i1 i2)) ;
|
||||
|
14
public-class-repo/SamplePrograms/Intervals/v4/intInterval.ml
Normal file
14
public-class-repo/SamplePrograms/Intervals/v4/intInterval.ml
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
(* Here use use the 'Make_interval' functor to create a module
|
||||
with types and functions for integer intervals. *)
|
||||
|
||||
open Intervals
|
||||
|
||||
module Int_interval =
|
||||
Make_interval (
|
||||
struct
|
||||
type t = int
|
||||
let compare = compare
|
||||
let to_string = string_of_int
|
||||
end )
|
||||
|
64
public-class-repo/SamplePrograms/Intervals/v4/intervals.ml
Normal file
64
public-class-repo/SamplePrograms/Intervals/v4/intervals.ml
Normal file
|
@ -0,0 +1,64 @@
|
|||
(* This code is the same as in Chapter 9 of Real World OCaml,
|
||||
except that we've added a 'to_string' function to the
|
||||
signature and modules.
|
||||
*)
|
||||
|
||||
(* We first create a signature, sometimes called an interface,
|
||||
indicating what types and values a module must have, at least,
|
||||
to be used as an end point in an interval.
|
||||
*)
|
||||
module type Comparable = sig
|
||||
type t
|
||||
val compare : t -> t -> int
|
||||
val to_string : t -> string
|
||||
end
|
||||
|
||||
|
||||
|
||||
(* The Make_interval functor takes a module that matches the
|
||||
Comparable signature and uses it to create an interval module over
|
||||
endpoint defined by that input module.
|
||||
*)
|
||||
module Make_interval(Endpoint : Comparable) = struct
|
||||
|
||||
type t = | Interval of Endpoint.t * Endpoint.t
|
||||
| Empty
|
||||
|
||||
(* 'create low high' creates a new interval from 'low' to
|
||||
'high'. If 'low > high', then the interval is empty *)
|
||||
let create low high =
|
||||
if Endpoint.compare low high > 0 then Empty
|
||||
else Interval (low,high)
|
||||
|
||||
(* Returns true iff the interval is empty *)
|
||||
let is_empty = function
|
||||
| Empty -> true
|
||||
| Interval _ -> false
|
||||
|
||||
(* 'contains t x' returns true iff 'x' is contained in the
|
||||
interval 't' *)
|
||||
let contains t x =
|
||||
match t with
|
||||
| Empty -> false
|
||||
| Interval (l,h) ->
|
||||
Endpoint.compare x l >= 0 && Endpoint.compare x h <= 0
|
||||
|
||||
(* 'intersect t1 t2' returns the intersection of the two input
|
||||
intervals *)
|
||||
let intersect t1 t2 =
|
||||
let min x y = if Endpoint.compare x y <= 0 then x else y in
|
||||
let max x y = if Endpoint.compare x y >= 0 then x else y in
|
||||
match t1,t2 with
|
||||
| Empty, _ | _, Empty -> Empty
|
||||
| Interval (l1,h1), Interval (l2,h2) ->
|
||||
create (max l1 l2) (min h1 h2)
|
||||
|
||||
let to_string i : string =
|
||||
match i with
|
||||
| Empty -> "Empty"
|
||||
| Interval (l,h)
|
||||
-> "(" ^ Endpoint.to_string l ^ ", " ^ Endpoint.to_string h ^ ")"
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
(* Here use use the 'Make_interval' functor to create a module
|
||||
with types and functions for string intervals. *)
|
||||
|
||||
open Intervals
|
||||
|
||||
module String_interval =
|
||||
Make_interval (
|
||||
struct
|
||||
type t = string
|
||||
let compare = compare
|
||||
let to_string x = x
|
||||
end )
|
||||
|
||||
|
||||
|
23
public-class-repo/SamplePrograms/Intervals/v4/useInterval.ml
Normal file
23
public-class-repo/SamplePrograms/Intervals/v4/useInterval.ml
Normal file
|
@ -0,0 +1,23 @@
|
|||
|
||||
open IntInterval
|
||||
open Intervals
|
||||
open StringInterval
|
||||
|
||||
let i1 = Int_interval.create 3 4
|
||||
|
||||
let i2 = Int_interval.create 3 6
|
||||
|
||||
let s1 = String_interval.create "a" "d"
|
||||
|
||||
let () =
|
||||
print_endline ("An interval: " ^ Int_interval.to_string i1) ;
|
||||
|
||||
print_endline ("Another interval: " ^ Int_interval.to_string i2) ;
|
||||
|
||||
print_endline ("Their intresection: " ^
|
||||
Int_interval.to_string (Int_interval.intersect i1 i2)) ;
|
||||
|
||||
print_endline ("A string interval: " ^ String_interval.to_string s1)
|
||||
|
||||
|
||||
|
28
public-class-repo/SamplePrograms/Intervals/v5/intInterval.ml
Normal file
28
public-class-repo/SamplePrograms/Intervals/v5/intInterval.ml
Normal file
|
@ -0,0 +1,28 @@
|
|||
|
||||
|
||||
open Intervals
|
||||
|
||||
module Int_interval = Make_interval(
|
||||
struct
|
||||
type t = int
|
||||
let compare = compare
|
||||
let to_string = string_of_int
|
||||
end)
|
||||
|
||||
|
||||
(* The following line causes an error.
|
||||
|
||||
We've provided 'create' the values of type 'int' and this is the
|
||||
same as Int.t' which is the same as EndPoint.t.
|
||||
|
||||
But 'endpoint' in Int_interval is bound to the type
|
||||
'Make_interval(Core.Std.Int).endpoint'
|
||||
|
||||
We've failed to indicate that the endpoint in Int_interval is
|
||||
related to the type in the Int module that is input to the
|
||||
Make_interval functor.
|
||||
|
||||
We also need to make sure this type is not hidden.
|
||||
*)
|
||||
let i = Int_interval.create 3 4
|
||||
|
71
public-class-repo/SamplePrograms/Intervals/v5/intervals.ml
Normal file
71
public-class-repo/SamplePrograms/Intervals/v5/intervals.ml
Normal file
|
@ -0,0 +1,71 @@
|
|||
|
||||
(* As before, we need to signature for endpoints. *)
|
||||
module type Comparable = sig
|
||||
type t
|
||||
val compare : t -> t -> int
|
||||
val to_string : t -> string
|
||||
end
|
||||
|
||||
|
||||
(* Now, define the signature that hides the type of the interval, named
|
||||
t below, and the type of the end points, named endpoint.
|
||||
*)
|
||||
module type Interval_intf = sig
|
||||
type t
|
||||
type endpoint
|
||||
val create : endpoint -> endpoint -> t
|
||||
val is_empty : t -> bool
|
||||
val contains : t -> endpoint -> bool
|
||||
val intersect : t -> t -> t
|
||||
val to_string : t -> string
|
||||
end
|
||||
|
||||
|
||||
(* The Make_interval functor takes a module that matches the
|
||||
Comparable signature and uses it to create an interval module over
|
||||
endpoint defined by that input module.
|
||||
*)
|
||||
module Make_interval(Endpoint : Comparable) : Interval_intf = struct
|
||||
|
||||
type endpoint = Endpoint.t
|
||||
|
||||
type t = | Interval of Endpoint.t * Endpoint.t
|
||||
| Empty
|
||||
|
||||
(** [create low high] creates a new interval from [low] to
|
||||
[high]. If [low > high], then the interval is empty *)
|
||||
let create low high =
|
||||
if Endpoint.compare low high > 0 then Empty
|
||||
else Interval (low,high)
|
||||
|
||||
(** Returns true iff the interval is empty *)
|
||||
let is_empty = function
|
||||
| Empty -> true
|
||||
| Interval _ -> false
|
||||
|
||||
(** [contains t x] returns true iff [x] is contained in the
|
||||
interval [t] *)
|
||||
let contains t x =
|
||||
match t with
|
||||
| Empty -> false
|
||||
| Interval (l,h) ->
|
||||
Endpoint.compare x l >= 0 && Endpoint.compare x h <= 0
|
||||
|
||||
(** [intersect t1 t2] returns the intersection of the two input
|
||||
intervals *)
|
||||
let intersect t1 t2 =
|
||||
let min x y = if Endpoint.compare x y <= 0 then x else y in
|
||||
let max x y = if Endpoint.compare x y >= 0 then x else y in
|
||||
match t1,t2 with
|
||||
| Empty, _ | _, Empty -> Empty
|
||||
| Interval (l1,h1), Interval (l2,h2) ->
|
||||
create (max l1 l2) (min h1 h2)
|
||||
|
||||
let to_string i : string =
|
||||
match i with
|
||||
| Empty -> "Empty"
|
||||
| Interval (l,h)
|
||||
-> "(" ^ Endpoint.to_string l ^ ", " ^ Endpoint.to_string h ^ ")"
|
||||
|
||||
end
|
||||
|
16
public-class-repo/SamplePrograms/Intervals/v6/intInterval.ml
Normal file
16
public-class-repo/SamplePrograms/Intervals/v6/intInterval.ml
Normal file
|
@ -0,0 +1,16 @@
|
|||
|
||||
open Intervals
|
||||
|
||||
module Int_comparable : (Comparable with type t = int) = struct
|
||||
type t = int
|
||||
let compare = compare
|
||||
let to_string = string_of_int
|
||||
end
|
||||
|
||||
module Int_interval = Make_interval(Int_comparable)
|
||||
|
||||
|
||||
|
||||
(* The following line now works. *)
|
||||
let i = Int_interval.create 3 4
|
||||
|
78
public-class-repo/SamplePrograms/Intervals/v6/intervals.ml
Normal file
78
public-class-repo/SamplePrograms/Intervals/v6/intervals.ml
Normal file
|
@ -0,0 +1,78 @@
|
|||
|
||||
(* As before, we need to signature for endpoints. *)
|
||||
module type Comparable = sig
|
||||
type t
|
||||
val compare : t -> t -> int
|
||||
val to_string : t -> string
|
||||
end
|
||||
|
||||
|
||||
(* Now, define the signature that hide the type of the interval, named
|
||||
t below, and the type of the end points, named endpoint.
|
||||
*)
|
||||
module type Interval_intf = sig
|
||||
type t
|
||||
type endpoint
|
||||
val create : endpoint -> endpoint -> t
|
||||
val is_empty : t -> bool
|
||||
val contains : t -> endpoint -> bool
|
||||
val intersect : t -> t -> t
|
||||
val to_string : t -> string
|
||||
end
|
||||
|
||||
|
||||
(* The Make_interval functor takes a module that matches the
|
||||
Comparable signature and uses it to create an interval module over
|
||||
endpoint defined by that input module.
|
||||
|
||||
****
|
||||
It also states the the 'endpoint' type in 'Interval_intf'
|
||||
is the same as the type 't' in the 'Endpoint' module passed
|
||||
in to 'Make_interval'
|
||||
*****
|
||||
*)
|
||||
module Make_interval(Endpoint : Comparable) :
|
||||
(Interval_intf with type endpoint = Endpoint.t) = struct
|
||||
|
||||
type endpoint = Endpoint.t
|
||||
|
||||
type t = | Interval of Endpoint.t * Endpoint.t
|
||||
| Empty
|
||||
|
||||
(** [create low high] creates a new interval from [low] to
|
||||
[high]. If [low > high], then the interval is empty *)
|
||||
let create low high =
|
||||
if Endpoint.compare low high > 0 then Empty
|
||||
else Interval (low,high)
|
||||
|
||||
(** Returns true iff the interval is empty *)
|
||||
let is_empty = function
|
||||
| Empty -> true
|
||||
| Interval _ -> false
|
||||
|
||||
(** [contains t x] returns true iff [x] is contained in the
|
||||
interval [t] *)
|
||||
let contains t x =
|
||||
match t with
|
||||
| Empty -> false
|
||||
| Interval (l,h) ->
|
||||
Endpoint.compare x l >= 0 && Endpoint.compare x h <= 0
|
||||
|
||||
(** [intersect t1 t2] returns the intersection of the two input
|
||||
intervals *)
|
||||
let intersect t1 t2 =
|
||||
let min x y = if Endpoint.compare x y <= 0 then x else y in
|
||||
let max x y = if Endpoint.compare x y >= 0 then x else y in
|
||||
match t1,t2 with
|
||||
| Empty, _ | _, Empty -> Empty
|
||||
| Interval (l1,h1), Interval (l2,h2) ->
|
||||
create (max l1 l2) (min h1 h2)
|
||||
|
||||
let to_string i : string =
|
||||
match i with
|
||||
| Empty -> "Empty"
|
||||
| Interval (l,h)
|
||||
-> "(" ^ Endpoint.to_string l ^ ", " ^ Endpoint.to_string h ^ ")"
|
||||
|
||||
end
|
||||
|
15
public-class-repo/SamplePrograms/Intervals/v7/intInterval.ml
Normal file
15
public-class-repo/SamplePrograms/Intervals/v7/intInterval.ml
Normal file
|
@ -0,0 +1,15 @@
|
|||
|
||||
open Intervals
|
||||
|
||||
module Int_comparable : (Comparable with type t = int) = struct
|
||||
type t = int
|
||||
let compare = compare
|
||||
let to_string = string_of_int
|
||||
end
|
||||
|
||||
module Int_interval = Make_interval(Int_comparable)
|
||||
|
||||
|
||||
(* The following line now works. *)
|
||||
let i = Int_interval.create 3 4
|
||||
|
81
public-class-repo/SamplePrograms/Intervals/v7/intervals.ml
Normal file
81
public-class-repo/SamplePrograms/Intervals/v7/intervals.ml
Normal file
|
@ -0,0 +1,81 @@
|
|||
|
||||
(* As before, we need to signature for endpoints. *)
|
||||
module type Comparable = sig
|
||||
type t
|
||||
val compare : t -> t -> int
|
||||
val to_string : t -> string
|
||||
end
|
||||
|
||||
|
||||
(* Now, define the signature that hide the type of the interval, named
|
||||
t below, and the type of the end points, named endpoint.
|
||||
*)
|
||||
module type Interval_intf = sig
|
||||
type t
|
||||
type endpoint
|
||||
val create : endpoint -> endpoint -> t
|
||||
val is_empty : t -> bool
|
||||
val contains : t -> endpoint -> bool
|
||||
val intersect : t -> t -> t
|
||||
val to_string : t -> string
|
||||
end
|
||||
|
||||
|
||||
(* The Make_interval functor takes a module that matches the
|
||||
Comparable signature and uses it to create an interval module over
|
||||
endpoint defined by that input module.
|
||||
|
||||
****
|
||||
It also states the the 'endpoint' type in 'Interval_intf'
|
||||
is replaced by hee type 't' in the 'Endpoint' module passed
|
||||
in to 'Make_interval'
|
||||
|
||||
In this case we used := instead of = to indicate this destructive
|
||||
substitution.
|
||||
*****
|
||||
*)
|
||||
module Make_interval(Endpoint : Comparable) :
|
||||
(Interval_intf with type endpoint := Endpoint.t) = struct
|
||||
|
||||
type endpoint = Endpoint.t
|
||||
|
||||
type t = | Interval of Endpoint.t * Endpoint.t
|
||||
| Empty
|
||||
|
||||
(** [create low high] creates a new interval from [low] to
|
||||
[high]. If [low > high], then the interval is empty *)
|
||||
let create low high =
|
||||
if Endpoint.compare low high > 0 then Empty
|
||||
else Interval (low,high)
|
||||
|
||||
(** Returns true iff the interval is empty *)
|
||||
let is_empty = function
|
||||
| Empty -> true
|
||||
| Interval _ -> false
|
||||
|
||||
(** [contains t x] returns true iff [x] is contained in the
|
||||
interval [t] *)
|
||||
let contains t x =
|
||||
match t with
|
||||
| Empty -> false
|
||||
| Interval (l,h) ->
|
||||
Endpoint.compare x l >= 0 && Endpoint.compare x h <= 0
|
||||
|
||||
(** [intersect t1 t2] returns the intersection of the two input
|
||||
intervals *)
|
||||
let intersect t1 t2 =
|
||||
let min x y = if Endpoint.compare x y <= 0 then x else y in
|
||||
let max x y = if Endpoint.compare x y >= 0 then x else y in
|
||||
match t1,t2 with
|
||||
| Empty, _ | _, Empty -> Empty
|
||||
| Interval (l1,h1), Interval (l2,h2) ->
|
||||
create (max l1 l2) (min h1 h2)
|
||||
|
||||
let to_string i : string =
|
||||
match i with
|
||||
| Empty -> "Empty"
|
||||
| Interval (l,h)
|
||||
-> "(" ^ Endpoint.to_string l ^ ", " ^ Endpoint.to_string h ^ ")"
|
||||
|
||||
end
|
||||
|
3
public-class-repo/SamplePrograms/README.md
Normal file
3
public-class-repo/SamplePrograms/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Sample Programs
|
||||
|
||||
Various sample OCaml programs will be placed here during the semester.
|
18
public-class-repo/SamplePrograms/Sec_01_1:25pm/arithmetic.ml
Normal file
18
public-class-repo/SamplePrograms/Sec_01_1:25pm/arithmetic.ml
Normal file
|
@ -0,0 +1,18 @@
|
|||
|
||||
type expr
|
||||
= Const of int
|
||||
| Add of expr * expr
|
||||
| Sub of expr * expr
|
||||
| Mul of expr * expr
|
||||
| Div of expr * expr
|
||||
|
||||
let rec eval (e:expr) : int =
|
||||
match e with
|
||||
| Const x -> x
|
||||
| Add (e1, e2) -> eval e1 + eval e2
|
||||
| Sub (e1, e2) -> eval e1 - eval e2
|
||||
| Mul (e1, e2) -> eval e1 * eval e2
|
||||
| Div (e1, e2) -> eval e1 / eval e2
|
||||
|
||||
let e1 = Add (Const 1, Mul (Const 2, Const 3))
|
||||
let e2 = Sub (Const 10, Div (e1, Const 2))
|
|
@ -0,0 +1,72 @@
|
|||
(* from Feb 13 *)
|
||||
|
||||
type 'a tree = Leaf of 'a
|
||||
| Fork of 'a * 'a tree * 'a tree
|
||||
|
||||
(* What are the pieces of the type definition above?
|
||||
|
||||
1. the name of the type constructor: tree
|
||||
|
||||
2. the arguments of the type constructor: 'a
|
||||
|
||||
3. the variants names: Leaf and Fork
|
||||
these are also called value constructors
|
||||
|
||||
4. the values associated with those names
|
||||
a. Leaf which holds a value of type 'a
|
||||
b. Fork which holds a value and two sub trees.
|
||||
|
||||
*)
|
||||
|
||||
|
||||
(* This is the 'monomorphic version - it only allows for integer trees
|
||||
and is much less general than the 'tree' above.*)
|
||||
type inttree = ILeaf of int
|
||||
| IFork of int * inttree * inttree
|
||||
|
||||
|
||||
|
||||
let t1 = Leaf 5
|
||||
let t2 = Fork (3, Leaf 3, Fork (2, t1, t1))
|
||||
let t3 = Fork ("Hello", Leaf "World", Leaf "!")
|
||||
|
||||
let rec size t =
|
||||
match t with
|
||||
| Leaf _ -> 1
|
||||
| Fork (_, ta, tb) -> 1 + size ta + size tb
|
||||
|
||||
let rec size' = fun t ->
|
||||
match t with
|
||||
| Leaf _ -> 1
|
||||
| Fork (_, ta, tb) -> 1 + size ta + size tb
|
||||
|
||||
let rec sum = function
|
||||
| Leaf v -> v
|
||||
| Fork (v, t1, t2) -> v + sum t1 + sum t2
|
||||
|
||||
|
||||
|
||||
let rec tfold (l:'a -> 'b) (f:'a -> 'b -> 'b -> 'b) (t:'a tree) : 'b =
|
||||
match t with
|
||||
| Leaf v -> l v
|
||||
| Fork (v, t1, t2) -> f v (tfold l f t1) (tfold l f t2)
|
||||
|
||||
let rec tmap (f:'a -> 'b) (t: 'a tree) : 'b tree = match t with
|
||||
| Leaf v -> Leaf (f v)
|
||||
| Fork (v, t1, t2) -> Fork (f v, tmap f t1, tmap f t2)
|
||||
|
||||
(* This is not the kind of folds that we want. It is better to have
|
||||
folds the have a function (or value) for each value constructor
|
||||
of the type. Thus `tfold` above has two functions, one for Leaf,
|
||||
one for Fork.
|
||||
|
||||
So don't write functions like the one below, at least not for creating
|
||||
general multi-purpose kinds of folding functions.
|
||||
*)
|
||||
let rec tfold' (f:'a -> 'b -> 'b) (accum:'b) (t:'a tree) : 'b =
|
||||
match t with
|
||||
| Leaf v -> f v accum
|
||||
| Fork (v, t1, t2) -> let l' = tfold' f accum t1 in
|
||||
let r' = tfold' f l' t2 in
|
||||
f v r'
|
||||
|
197
public-class-repo/SamplePrograms/Sec_01_1:25pm/continuation.ml
Normal file
197
public-class-repo/SamplePrograms/Sec_01_1:25pm/continuation.ml
Normal file
|
@ -0,0 +1,197 @@
|
|||
(* Continuation passing style is another mechanism for improving
|
||||
performance.
|
||||
|
||||
Many of these are from Charlie Harper.
|
||||
*)
|
||||
|
||||
|
||||
|
||||
type 'a tree = Empty
|
||||
| Fork of 'a tree * 'a * 'a tree
|
||||
|
||||
let t =
|
||||
Fork (
|
||||
Fork (
|
||||
Fork ( Empty, 1, Empty ),
|
||||
2,
|
||||
Fork ( Empty, 3, Empty )
|
||||
),
|
||||
4,
|
||||
Fork (
|
||||
Fork ( Empty, 5, Empty ),
|
||||
6,
|
||||
Fork ( Empty, 7, Empty )
|
||||
)
|
||||
)
|
||||
|
||||
let rec flatten t = match t with
|
||||
| Empty -> []
|
||||
| Fork (t1, v, t2) -> flatten t1 @ [v] @ flatten t2
|
||||
|
||||
|
||||
(* How can we improve the performance of this function? *)
|
||||
|
||||
(* Here the extra parameter is not accumulating the result.
|
||||
That is, we don't perform an operation on it directly.
|
||||
|
||||
It is a continuation for the result.
|
||||
|
||||
We keep adding to it.
|
||||
*)
|
||||
|
||||
let flatten_c t =
|
||||
let rec flatten_with t c = match t with
|
||||
| Empty -> c
|
||||
| Fork (t1, v, t2) -> flatten_with t1 (v :: flatten_with t2 c)
|
||||
in
|
||||
flatten_with t []
|
||||
|
||||
|
||||
|
||||
|
||||
(* When we speak of "continuation passing style" we typically
|
||||
mean passing a continuation that is a function.
|
||||
*)
|
||||
|
||||
|
||||
let ident x = x
|
||||
|
||||
let tail_fact n =
|
||||
let rec tail_fact_rec n k = match n with
|
||||
| 0 -> k 1
|
||||
| _ -> tail_fact_rec (n-1) (fun r -> k (r*n))
|
||||
in
|
||||
tail_fact_rec n ident
|
||||
|
||||
exception InvalidArgument
|
||||
|
||||
|
||||
|
||||
(* This one is not quite so basic, but that's what you
|
||||
get when linearizing traversals of bifurcating paths. *)
|
||||
|
||||
let tail_fib n =
|
||||
let rec tail_fib_rec n k =
|
||||
match n with
|
||||
| 0 -> k 0
|
||||
| 1 -> k 1
|
||||
| n -> tail_fib_rec
|
||||
(n - 1)
|
||||
(fun rn1 ->
|
||||
tail_fib_rec
|
||||
(n - 2)
|
||||
(fun rn2 ->
|
||||
(k (rn1 + rn2))) )
|
||||
in
|
||||
if n >= 0
|
||||
then tail_fib_rec n ident
|
||||
else raise InvalidArgument
|
||||
|
||||
(*
|
||||
tfr 3 id
|
||||
tfr 2 c1
|
||||
where c1 = (\rn1 -> tfr 1 (\rn2 -> id (rn1 + rn2)))
|
||||
tfr 1 c2
|
||||
where c1 = (\rn1 -> tfr 1 (\rn2 -> id (rn1 + rn2)))
|
||||
where c2 = (\rn1 -> tfr 0 (\rn2 -> c1 (rn1 + rn2)))
|
||||
c2 1
|
||||
where c1 = (\rn1 -> tfr 1 (\rn2 -> id (rn1 + rn2)))
|
||||
where c2 = (\rn1 -> tfr 0 (\rn2 -> c1 (rn1 + rn2)))
|
||||
(\rn1 -> tfr 0 (\rn2 -> c1 (rn1 + rn2))) 1
|
||||
where c1 = (\rn1 -> tfr 1 (\rn2 -> id (rn1 + rn2)))
|
||||
tfr 0 (\rn2 -> c1 (1 + rn2))
|
||||
where c1 = (\rn1 -> tfr 1 (\rn2 -> id (rn1 + rn2)))
|
||||
tfr 0 c3
|
||||
where c1 = (\rn1 -> tfr 1 (\rn2 -> id (rn1 + rn2)))
|
||||
where c3 = (\rn2 -> c1 (1 + rn2))
|
||||
c3 0
|
||||
where c1 = (\rn1 -> tfr 1 (\rn2 -> id (rn1 + rn2)))
|
||||
where c3 = (\rn2 -> c1 (1 + rn2))
|
||||
(\rn2 -> c1 (1 + rn2)) 0
|
||||
where c1 = (\rn1 -> tfr 1 (\rn2 -> id (rn1 + rn2)))
|
||||
c1 (1 + 0)
|
||||
where c1 = (\rn1 -> tfr 1 (\rn2 -> id (rn1 + rn2)))
|
||||
c1 1
|
||||
where c1 = (\rn1 -> tfr 1 (\rn2 -> id (rn1 + rn2)))
|
||||
(\rn1 -> tfr 1 (\rn2 -> id (rn1 + rn2))) 1
|
||||
tfr 1 (\rn2 -> id (1 + rn2))
|
||||
(\rn2 -> id (1 + rn2)) 1
|
||||
id (1 + 1)
|
||||
2
|
||||
|
||||
*)
|
||||
|
||||
let sum_range f low high step =
|
||||
let rec sum_range_rec x k =
|
||||
if x <= high
|
||||
then sum_range_rec (x + step) (fun r -> k (r + f x))
|
||||
else k 0
|
||||
in
|
||||
if low > high
|
||||
then raise InvalidArgument
|
||||
else sum_range_rec low ident
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(* Really useful for these, since the continuations allow the lists
|
||||
and values to be constructed in the correct patterns, especially
|
||||
for lists being recursively constructed non-reversed without
|
||||
using list concatenation. *)
|
||||
|
||||
let rec map f lst =
|
||||
match lst with
|
||||
| [] -> []
|
||||
| h::t -> f h :: map f t
|
||||
|
||||
(* Exercise: write a tail recursive version of map. *)
|
||||
|
||||
let map_c f lst =
|
||||
let rec mc f lst k =
|
||||
match lst with
|
||||
| [] -> k []
|
||||
| x::xs -> mc f xs (fun r -> k (f x :: r))
|
||||
in
|
||||
mc f lst ident
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
let tail_fold_right f lst v =
|
||||
let rec tail_fr_rec l k =
|
||||
match l with
|
||||
| an::[] -> k (f an v)
|
||||
| a::t -> tail_fr_rec t (fun r -> k (f a r))
|
||||
| _ -> v in (* never goes down this branch *)
|
||||
match lst with
|
||||
| [] -> v
|
||||
| _ -> tail_fr_rec lst ident
|
||||
|
||||
|
||||
let tail_filter f lst =
|
||||
let rec tail_filter_rec l k =
|
||||
match l with
|
||||
| [] -> k []
|
||||
| h::t when f h -> tail_filter_rec t (fun r -> k (h::r))
|
||||
| _::t -> tail_filter_rec t k in
|
||||
tail_filter_rec lst ident
|
||||
|
||||
(* A rewrite of tail_filter showing how some of the business logic of
|
||||
the problem can be moved into and out of the continuation. *)
|
||||
let tail_filter2 f lst =
|
||||
let rec tail_filter_rec l k =
|
||||
match l with
|
||||
| [] -> k []
|
||||
| h::t ->
|
||||
tail_filter_rec
|
||||
t
|
||||
(fun r -> if f h then k (h::r) else k r)
|
||||
in
|
||||
tail_filter_rec lst ident
|
||||
|
||||
|
||||
|
18
public-class-repo/SamplePrograms/Sec_01_1:25pm/estring.ml
Normal file
18
public-class-repo/SamplePrograms/Sec_01_1:25pm/estring.ml
Normal file
|
@ -0,0 +1,18 @@
|
|||
type estring = char list
|
||||
|
||||
|
||||
let rec explode = function
|
||||
| "" -> []
|
||||
| s -> String.get s 0 :: explode (String.sub s 1 ((String.length s) - 1))
|
||||
|
||||
let rec implode = function
|
||||
| [] -> ""
|
||||
| c::cs -> String.make 1 c ^ implode cs
|
||||
|
||||
|
||||
(* Modifed from functions found at http://www.csc.villanova.edu/~dmatusze/8310summer2001/assignments/ocaml-functions.html *)
|
||||
|
||||
let freshperson cs =
|
||||
let helper c = if c = '.' || c = '!' then '?' else c
|
||||
in
|
||||
map helper cs
|
33
public-class-repo/SamplePrograms/Sec_01_1:25pm/eval.ml
Normal file
33
public-class-repo/SamplePrograms/Sec_01_1:25pm/eval.ml
Normal file
|
@ -0,0 +1,33 @@
|
|||
type expr
|
||||
= Add of expr * expr
|
||||
| Sub of expr * expr
|
||||
| Mul of expr * expr
|
||||
| Div of expr * expr
|
||||
|
||||
| Lt of expr * expr
|
||||
| Eq of expr * expr
|
||||
| And of expr * expr
|
||||
| Not of expr
|
||||
| If of expr * expr * expr
|
||||
|
||||
| Let of string * expr * expr
|
||||
| Id of string
|
||||
|
||||
| App of expr * expr
|
||||
| Lambda of string * expr
|
||||
|
||||
| Value of value
|
||||
and value
|
||||
= Int of int
|
||||
| Bool of bool
|
||||
|
|
||||
|
||||
(* let add = fun x -> fun y -> x + y
|
||||
let add x y = x + y *)
|
||||
let add = Lambda ("x", Lambda( "y", Add (Id "x", Id "y")))
|
||||
|
||||
let inc = Lambda ("x", Add (Id "x", Value (Int 1)))
|
||||
|
||||
let two = App inc (Value (Int 1))
|
||||
|
||||
|
36
public-class-repo/SamplePrograms/Sec_01_1:25pm/expr_let.ml
Normal file
36
public-class-repo/SamplePrograms/Sec_01_1:25pm/expr_let.ml
Normal file
|
@ -0,0 +1,36 @@
|
|||
type expr
|
||||
= Const of int
|
||||
| Add of expr * expr
|
||||
| Sub of expr * expr
|
||||
| Mul of expr * expr
|
||||
| Div of expr * expr
|
||||
|
||||
| Let of string * expr * expr
|
||||
| Id of string
|
||||
|
||||
type environment = (string * int) list
|
||||
|
||||
let rec lookup (n:string) (env: environment) : int =
|
||||
match env with
|
||||
| [] -> raise (Failure ("Identifier " ^ n ^ " not in scope"))
|
||||
| (n',v) :: rest when n = n' -> v
|
||||
| _ :: rest -> lookup n rest
|
||||
|
||||
let rec eval (env: environment) (e:expr) : int =
|
||||
match e with
|
||||
| Const x -> x
|
||||
| Add (e1, e2) -> eval env e1 + eval env e2
|
||||
| Sub (e1, e2) -> eval env e1 - eval env e2
|
||||
| Mul (e1, e2) -> eval env e1 * eval env e2
|
||||
| Div (e1, e2) -> eval env e1 / eval env e2
|
||||
| Let (n, dexpr, body) ->
|
||||
let dexpr_v = eval env dexpr in
|
||||
let body_v = eval ((n,dexpr_v)::env) body in
|
||||
body_v
|
||||
|
||||
| Id n -> lookup n env
|
||||
|
||||
let e1 = Add (Const 1, Mul (Const 2, Const 3))
|
||||
let e2 = Sub (Const 10, Div (e1, Const 2))
|
||||
let e3 = Let ("x", Const 5, Add (Id "x", Const 4))
|
||||
let e4 = Let ("y", Const 5, Let ("x", Add (Id "y", Const 5), Add (Id "x", Id "y")))
|
18
public-class-repo/SamplePrograms/Sec_01_1:25pm/filter.ml
Normal file
18
public-class-repo/SamplePrograms/Sec_01_1:25pm/filter.ml
Normal file
|
@ -0,0 +1,18 @@
|
|||
|
||||
let rec filter f l =
|
||||
match l with
|
||||
| [] -> []
|
||||
| x::xs ->
|
||||
let rest = filter f xs
|
||||
in
|
||||
if f x
|
||||
then x :: rest
|
||||
else rest
|
||||
|
||||
let rec filter' f l =
|
||||
match l with
|
||||
| [] -> []
|
||||
| x::xs when f x -> x :: filter f xs
|
||||
| x::xs -> filter f xs
|
||||
|
||||
let filter_out f l = filter (fun v -> not (f v)) l
|
|
@ -0,0 +1,57 @@
|
|||
let m = [ ("dog", 1); ("chicken",2); ("dog",3); ("cat",5)]
|
||||
|
||||
let rec lookup_all s m =
|
||||
match m with
|
||||
| [] -> []
|
||||
| (name,value)::ms ->
|
||||
let rest = lookup_all s ms
|
||||
in if s = name then value :: rest else rest
|
||||
|
||||
(* find all by : (’a -> ’a ->bool) -> ’a ->
|
||||
’a list -> ’a list
|
||||
*)
|
||||
|
||||
let streq s1 s2 = s1 = s2
|
||||
let check (s2,v) s1 = s1 = s2
|
||||
let rec find_all_by equals v lst =
|
||||
match lst with
|
||||
| [] -> []
|
||||
| x::xs when equals x v -> x :: find_all_by equals v xs
|
||||
| x::xs -> find_all_by equals v xs
|
||||
|
||||
let rec snds l =
|
||||
match l with
|
||||
| [] -> []
|
||||
| (v1,v2)::rest -> v2 :: snds rest
|
||||
|
||||
let lookup_all' s m = snds (find_all_by check s m)
|
||||
|
||||
let is_elem_by equals e l =
|
||||
match find_all_by equals e l with
|
||||
| [] -> false
|
||||
| _::_ -> true
|
||||
|
||||
|
||||
let rec find_all_with f l =
|
||||
match l with
|
||||
| [] -> []
|
||||
| x::xs ->
|
||||
let rest = find_all_with f xs
|
||||
in if f x then x::rest else rest
|
||||
|
||||
let find_all_by' eq v l = find_all_with (fun x -> eq x v) l
|
||||
|
||||
let find_all_by'' eq v = find_all_with (fun x -> eq x v)
|
||||
|
||||
let find_all_with' f l = find_all_by (fun x y -> f x = y) true
|
||||
|
||||
let find_all x = find_all_with ((=) x)
|
||||
|
||||
(* drop while: ’a list -> (’a -> bool) -> ’a list
|
||||
|
||||
drop_while ( (=) 4 ) [4;4;4;5;6;7] = [5;6;7] *)
|
||||
|
||||
let rec drop_while l f =
|
||||
match l with
|
||||
| [] -> []
|
||||
| v::rest -> if f v then drop_while rest f else v::rest
|
50
public-class-repo/SamplePrograms/Sec_01_1:25pm/fold.ml
Normal file
50
public-class-repo/SamplePrograms/Sec_01_1:25pm/fold.ml
Normal file
|
@ -0,0 +1,50 @@
|
|||
(* Sec 01, Feb 3 *)
|
||||
|
||||
(*
|
||||
fold (+) 0 [1;2;3;4]
|
||||
We can see this as
|
||||
1 + (2 + (3 + (4 + 0)))
|
||||
*)
|
||||
|
||||
let rec fold_v1 f e l =
|
||||
match l with
|
||||
| [] -> e
|
||||
| x::xs -> f x (fold_v1 f e xs)
|
||||
|
||||
let f : (int -> string -> string) =
|
||||
fun x -> fun s -> string_of_int x ^ ", " ^ s
|
||||
|
||||
|
||||
(* fold (+) 0 [1;2;3;4]
|
||||
as
|
||||
((((0 + 1) + 2) + 3) + 4)
|
||||
*)
|
||||
|
||||
let rec fold_v2 f e lst =
|
||||
match lst with
|
||||
| [] -> e
|
||||
| hd::tail -> fold_v2 f (f e hd) tail
|
||||
|
||||
|
||||
let g : (string -> int -> string) =
|
||||
fun s -> fun x -> s ^ ", " ^ string_of_int x
|
||||
|
||||
|
||||
(* Below are the versions of these functions from the slides. They
|
||||
are the same excpet for their names. Below we chose 'l' and 'r' to
|
||||
indicate if we are folding lists up from the left of from the
|
||||
right. *)
|
||||
|
||||
let rec foldr (f:'a -> 'b -> 'b) (l:'a list) (v:'b) : 'b =
|
||||
match l with
|
||||
| [] -> v
|
||||
| x::xs -> f x (foldr f xs v)
|
||||
|
||||
(* Notice how 'f' replaces '::' and 'v' replaces '[]' *)
|
||||
|
||||
let rec foldl f v l =
|
||||
match l with
|
||||
| [] -> v
|
||||
| x::xs -> foldl f (f v x) xs
|
||||
|
||||
let length (lst: 'a list) : int = foldl (fun n _ -> n + 1 ) 0 lst
|
92
public-class-repo/SamplePrograms/Sec_01_1:25pm/inductive.ml
Normal file
92
public-class-repo/SamplePrograms/Sec_01_1:25pm/inductive.ml
Normal file
|
@ -0,0 +1,92 @@
|
|||
(*
|
||||
Some sample evaluations from the exercises on Feb 6.
|
||||
|
||||
let x = 1 + 2 in let y = x + 3 in x + y
|
||||
|
||||
let x = 3 in let y = x + 3 in x + y
|
||||
|
||||
let x = 3 in let y = 3 + 3 in 3 + y
|
||||
|
||||
let x = 3 in let y = 6 in 3 + y
|
||||
|
||||
let x = 3 in let y = 6 in 3 + 6
|
||||
|
||||
let y = 6 in 3 + 6
|
||||
|
||||
3 + 6
|
||||
|
||||
9
|
||||
|
||||
|
||||
|
||||
let rec rev = function
|
||||
| [] -> []
|
||||
| x::xs -> rev xs @ [x]
|
||||
|
||||
rev (1::2::3::[])
|
||||
|
||||
rev (2::3::[]) @ [1]
|
||||
|
||||
(rev (3::[]) @ [2]) @ [1]
|
||||
|
||||
rev ([]) @ [3] @ [2] @ [1]
|
||||
|
||||
(([] @ [3]) @ [2]) @ [1]
|
||||
|
||||
([3] @ [2]) @ [1]
|
||||
|
||||
[3; 2] @ [1]
|
||||
|
||||
[3;2;1]
|
||||
|
||||
*)
|
||||
|
||||
|
||||
type color = Red
|
||||
| Green
|
||||
| Blue
|
||||
|
||||
let isRed d =
|
||||
match d with
|
||||
Red -> true
|
||||
| _-> false
|
||||
|
||||
|
||||
|
||||
|
||||
type days = Sunday
|
||||
| Monday
|
||||
| Tuesday
|
||||
| Wednesday
|
||||
| Thursday
|
||||
| Friday
|
||||
| Saturday
|
||||
|
||||
let isWeekDay d =
|
||||
match d with
|
||||
| Sunday | Saturday -> false
|
||||
| Monday | Tuesday | Wednesday | Thursday | Friday -> true
|
||||
|
||||
type intorstr = Int of int
|
||||
| Str of string
|
||||
|
||||
(* this has the same functionality as the one in the slides *)
|
||||
let rec sumList l =
|
||||
match l with
|
||||
| [] -> 0
|
||||
| (Int i):: tl -> i + sumList tl
|
||||
| (Str s):: tl -> sumList tl
|
||||
|
||||
|
||||
(* The OCaml standard library offers the following type:
|
||||
type 'a option = None
|
||||
| Some of 'a
|
||||
|
||||
It is useful for so-called "optional" values. These are useful in
|
||||
circumstances when a function may return a value, but it might not.
|
||||
A function that is to read the contents of a file, for example. It
|
||||
may be successful and return a string or char list, or the file
|
||||
might not be found and thus it doesn't return a value.
|
||||
|
||||
*)
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
type expr
|
||||
= Add of expr * expr
|
||||
| Sub of expr * expr
|
||||
| Mul of expr * expr
|
||||
| Div of expr * expr
|
||||
|
||||
| Lt of expr * expr
|
||||
| Eq of expr * expr
|
||||
| And of expr * expr
|
||||
| Not of expr
|
||||
|
||||
| If of expr * expr * expr
|
||||
|
||||
| Let of string * expr * expr
|
||||
| Id of string
|
||||
|
||||
| Value of value
|
||||
and value
|
||||
= Int of int
|
||||
| Bool of bool
|
||||
|
||||
|
||||
(* freevars (Add(Id "x", Value (Int 3))) ---->> ["x"]
|
||||
freevars (Let ("x", Id "y", (Add(Id "x", Value (Int 3))))) ---->> ["y"] *)
|
||||
let rec freevars (e:expr) : string list =
|
||||
match e with
|
||||
| Value v -> []
|
||||
| Add (e1, e2) -> freevars e1 @ freevars e2
|
||||
| Let (i, dexpr, body) ->
|
||||
freevars dexpr @ List.filter (fun i' -> i' <> i) (freevars body)
|
||||
| Id i -> [i]
|
||||
|
||||
|
||||
type environment = (string * value) list
|
||||
|
||||
let rec eval (env:environment) (e:expr) : value =
|
||||
match e with
|
||||
| Value v -> v
|
||||
| Add (e1, e2) ->
|
||||
( match eval env e1, eval env e2 with
|
||||
| Int i1, Int i2 -> Int (i1 + i2)
|
||||
| _, _ -> raise (Failure "incompatible type on Add")
|
||||
)
|
||||
| Sub (e1, e2) ->
|
||||
( match eval env e1, eval env e2 with
|
||||
| Int i1, Int i2 -> Int (i1 - i2)
|
||||
| _, _ -> raise (Failure "incompatible type on Sub")
|
||||
)
|
||||
| Lt (e1, e2) ->
|
||||
( match eval env e1, eval env e2 with
|
||||
| Int i1, Int i2 -> Bool (i1 < i2)
|
||||
| _, _ -> raise (Failure "incompatible type on Lt")
|
||||
)
|
||||
|
||||
let e1 = Add (Value (Int 1), Sub (Value (Int 10), Value (Int 3)))
|
||||
|
165
public-class-repo/SamplePrograms/Sec_01_1:25pm/interpreter.ml
Normal file
165
public-class-repo/SamplePrograms/Sec_01_1:25pm/interpreter.ml
Normal file
|
@ -0,0 +1,165 @@
|
|||
type value
|
||||
= Int of int
|
||||
| Bool of bool
|
||||
|
||||
type expr =
|
||||
| Add of expr * expr
|
||||
| Mul of expr * expr
|
||||
| Sub of expr * expr
|
||||
| Div of expr * expr
|
||||
|
||||
| Lt of expr * expr
|
||||
| Eq of expr * expr
|
||||
| And of expr * expr
|
||||
|
||||
| Var of string
|
||||
| Value of value
|
||||
|
||||
type environment = (string * value) list
|
||||
|
||||
let rec lookup name env =
|
||||
match env with
|
||||
| [ ] -> raise (Failure ("Name \"" ^ name ^ "\" not found."))
|
||||
| (k,v)::rest -> if name = k then v else lookup name rest
|
||||
|
||||
let rec eval (e: expr) (env: environment) : value =
|
||||
match e with
|
||||
| Value v -> v
|
||||
| Add (e1, e2) ->
|
||||
( match eval e1 env, eval e2 env with
|
||||
| Int v1, Int v2 -> Int (v1 + v2)
|
||||
| _ -> raise (Failure "incompatible types, Add")
|
||||
)
|
||||
| Sub (e1, e2) ->
|
||||
( match eval e1 env, eval e2 env with
|
||||
| Int v1, Int v2 -> Int (v1 - v2)
|
||||
| _ -> raise (Failure "incompatible types, Sub")
|
||||
)
|
||||
| Mul (e1, e2) ->
|
||||
( match eval e1 env, eval e2 env with
|
||||
| Int v1, Int v2 -> Int (v1 * v2)
|
||||
| _ -> raise (Failure "incompatible types, Mul")
|
||||
)
|
||||
| Div (e1, e2) ->
|
||||
( match eval e1 env, eval e2 env with
|
||||
| Int v1, Int v2 -> Int (v1 / v2)
|
||||
| _ -> raise (Failure "incompatible types, Div")
|
||||
)
|
||||
| Lt (e1, e2) ->
|
||||
( match eval e1 env, eval e2 env with
|
||||
| Int v1, Int v2 -> Bool (v1 < v2)
|
||||
| _ -> raise (Failure "incompatible types, Lt")
|
||||
)
|
||||
| Eq (e1, e2) ->
|
||||
( match eval e1 env, eval e2 env with
|
||||
| Int v1, Int v2 -> Bool (v1 = v2)
|
||||
| Bool v1, Bool v2 -> Bool (v1 = v2)
|
||||
| _ -> raise (Failure "incompatible types, Eq")
|
||||
)
|
||||
| And (e1, e2) ->
|
||||
( match eval e1 env, eval e2 env with
|
||||
| Bool v1, Bool v2 -> Bool (v1 && v2)
|
||||
| _ -> raise (Failure "incompatible types, And")
|
||||
)
|
||||
| Var n -> lookup n env
|
||||
|
||||
|
||||
|
||||
type state = environment
|
||||
|
||||
type stmt =
|
||||
| Assign of string * expr
|
||||
| While of expr * stmt
|
||||
| IfThen of expr * stmt
|
||||
| IfThenElse of expr * stmt * stmt
|
||||
| Seq of stmt * stmt
|
||||
| WriteNum of expr
|
||||
| ReadNum of string
|
||||
|
||||
(* x := 1;
|
||||
y := x + 2;
|
||||
z := y + 3;
|
||||
write z
|
||||
*)
|
||||
let program_1 =
|
||||
Seq ( Assign ("x", Value (Int 1)) ,
|
||||
Seq ( Assign ("y", Add (Var "x", Value (Int 2))),
|
||||
Seq ( Assign ("z", Add (Var "y", Value (Int 3))),
|
||||
WriteNum (Var "z")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
(* read x;
|
||||
i = 0;
|
||||
sum = 0;
|
||||
while (i < x) {
|
||||
write i;
|
||||
sum = sum + i;
|
||||
i = i + 1
|
||||
}
|
||||
write sum
|
||||
*)
|
||||
|
||||
let program_2 =
|
||||
Seq (ReadNum "x",
|
||||
Seq (Assign ("i", Value (Int 0)),
|
||||
Seq (Assign ("sum", Value (Int 0)),
|
||||
Seq (While (Lt (Var "i", Var "x"),
|
||||
Seq (WriteNum (Var "i"),
|
||||
Seq (Assign ("sum", Add (Var "sum", Var "i")),
|
||||
Assign ("i", Add (Var "i", Value (Int 1)))
|
||||
) ) ),
|
||||
WriteNum (Var "sum")
|
||||
) ) ) )
|
||||
|
||||
|
||||
(* program_3
|
||||
|
||||
read x;
|
||||
i = 0;
|
||||
sum_evens = 0;
|
||||
sum_odds = 0;
|
||||
while (i < x) {
|
||||
write i;
|
||||
if i mod 2 = 0 then
|
||||
sum_evens = sum_evens + i;
|
||||
else
|
||||
sum_odds = sum_odds + i;
|
||||
i = i + 1
|
||||
}
|
||||
write sum_evens;
|
||||
write sum_odds
|
||||
*)
|
||||
|
||||
let rec read_number () =
|
||||
print_endline "Enter an integer value:" ;
|
||||
try int_of_string (read_line ()) with
|
||||
| Failure _ -> read_number ()
|
||||
|
||||
let write_number n = print_endline (string_of_int n)
|
||||
|
||||
|
||||
let rec exec (s: stmt) (stt: state) : state =
|
||||
match s with
|
||||
| Assign (v, e) -> (v, (eval e stt)) :: stt
|
||||
|
||||
| Seq (s1, s2) -> exec s2 (exec s1 stt)
|
||||
|
||||
| WriteNum e -> (match eval e stt with
|
||||
| Int v -> write_number v; stt
|
||||
| _ -> raise (Failure "Only numeric values can be printed.")
|
||||
)
|
||||
|
||||
| ReadNum v -> (v, Int (read_number ())) :: stt
|
||||
|
||||
| While (cond, body) ->
|
||||
(match eval cond stt with
|
||||
| Bool true -> exec (Seq (body, While (cond, body))) stt
|
||||
(* the version in the Sec_10 directory is slighlty
|
||||
different, but achieves the same results. *)
|
||||
| Bool false -> stt
|
||||
)
|
||||
|
||||
|
46
public-class-repo/SamplePrograms/Sec_01_1:25pm/jan_25.ml
Normal file
46
public-class-repo/SamplePrograms/Sec_01_1:25pm/jan_25.ml
Normal file
|
@ -0,0 +1,46 @@
|
|||
let is_empty_1 l =
|
||||
if l = [] then true else false
|
||||
|
||||
let is_empty_2 l =
|
||||
match l with
|
||||
| [] -> true
|
||||
| _ -> false
|
||||
|
||||
let is_empty3 l = l = []
|
||||
|
||||
let head l =
|
||||
match l with
|
||||
| [] -> None
|
||||
| h::_ -> Some h
|
||||
|
||||
let head' l =
|
||||
match l with
|
||||
| [] -> raise (Failure "hey, genius, your list was empty")
|
||||
| h::_ -> h
|
||||
|
||||
let rec drop_value td l =
|
||||
match l with
|
||||
| [] -> []
|
||||
| h::t when h = td -> drop_value td t
|
||||
| h::t -> h :: drop_value td t
|
||||
|
||||
let both_empty l1 l2 =
|
||||
match (l1, l2) with
|
||||
| ([], []) -> true
|
||||
| (_, _ ) -> false
|
||||
|
||||
|
||||
(*
|
||||
Can you complete lookup_all?
|
||||
let rec lookup_all v l =
|
||||
match l with
|
||||
| [] -> []
|
||||
| (key,value)::rest when key = v -> ......
|
||||
*)
|
||||
|
||||
|
||||
let rec fib x =
|
||||
match x with
|
||||
| 0 -> 0
|
||||
| 1 -> 1
|
||||
| n -> fib(n-1) + fib(n-2)
|
5
public-class-repo/SamplePrograms/Sec_01_1:25pm/map.ml
Normal file
5
public-class-repo/SamplePrograms/Sec_01_1:25pm/map.ml
Normal file
|
@ -0,0 +1,5 @@
|
|||
|
||||
let rec map f l =
|
||||
match l with
|
||||
| [] -> []
|
||||
| x::xs -> f x :: map f xs
|
6
public-class-repo/SamplePrograms/Sec_01_1:25pm/nat.ml
Normal file
6
public-class-repo/SamplePrograms/Sec_01_1:25pm/nat.ml
Normal file
|
@ -0,0 +1,6 @@
|
|||
type nat = Zero | Succ of nat
|
||||
|
||||
let rec toInt n = match n with
|
||||
| Zero -> 0
|
||||
| Succ n' -> 1 + toInt n'
|
||||
|
30
public-class-repo/SamplePrograms/Sec_01_1:25pm/references.ml
Normal file
30
public-class-repo/SamplePrograms/Sec_01_1:25pm/references.ml
Normal file
|
@ -0,0 +1,30 @@
|
|||
(* Construct a circular structure of the form
|
||||
|
||||
c --> 1 --> 2 --> 3
|
||||
^ |
|
||||
| |
|
||||
+---------------+
|
||||
Write a function that returns the first n elements.
|
||||
|
||||
Each number above should be a pair with an int and a reference to the
|
||||
next pair.
|
||||
*)
|
||||
|
||||
type box = Box of int * box ref
|
||||
let rec dummy : box = Box (999, ref dummy)
|
||||
|
||||
let c =
|
||||
let ref_in_one = ref dummy in
|
||||
let one = Box (1, ref_in_one) in
|
||||
let three = Box (3, ref one) in
|
||||
let two = Box (2, ref three) in
|
||||
let () = ref_in_one := two in
|
||||
ref one
|
||||
|
||||
let rec c' =
|
||||
Box (1, ref (Box (2, ref (Box (3, ref c')))))
|
||||
|
||||
let rec first_n (n:int) (b:box) : int list =
|
||||
match n, b with
|
||||
| 0, _ -> []
|
||||
| _, Box (v, nb) -> v :: first_n (n-1) (!nb)
|
|
@ -0,0 +1,199 @@
|
|||
|
||||
let s = [ 1; 3; -2; 5; -6 ] (* sample set from the S6 slides *)
|
||||
|
||||
let sum lst = List.fold_left (+) 0 lst
|
||||
|
||||
(* Now, is_elem which is used in processing the solution *)
|
||||
let is_elem v l =
|
||||
List.fold_right (fun x in_rest -> if x = v then true else in_rest) l false
|
||||
|
||||
let rec explode = function
|
||||
| "" -> []
|
||||
| s -> String.get s 0 :: explode (String.sub s 1 ((String.length s) - 1))
|
||||
|
||||
let rec implode = function
|
||||
| [] -> ""
|
||||
| c::cs -> String.make 1 c ^ implode cs
|
||||
|
||||
let show_list show l =
|
||||
let rec sl l =
|
||||
match l with
|
||||
| [] -> ""
|
||||
| [x] -> show x
|
||||
| x::xs -> show x ^ "; " ^ sl xs
|
||||
in "[ " ^ sl l ^ " ]"
|
||||
|
||||
(* ---
|
||||
Exceptions
|
||||
---
|
||||
*)
|
||||
|
||||
|
||||
(* We can also use exceptions in searching. This goes against the
|
||||
general principle of only throwing an exception for truly
|
||||
unexpected results, but it does make writing the code a bit more
|
||||
convenient, so we will use them in this non-traditional way.
|
||||
|
||||
An exception is thrown when we've found the value that we want and
|
||||
this quickly returns us to the top level where we can then report
|
||||
success.
|
||||
|
||||
We now execute the two recursive calls to 'try_subset' in sequence,
|
||||
not needing to inspect the output of the first one. If the first
|
||||
call finds a solution then it will raise an exception. So we
|
||||
don't care about the value returned by that first call. If it
|
||||
returns it only does so if it didn't find a solution, in which case
|
||||
we want to just keep searching.
|
||||
*)
|
||||
|
||||
exception FoundSubSet of int list
|
||||
|
||||
|
||||
(* OCaml's ";" expects a unit value on the left, so run evaluates an
|
||||
expression but discards its result. This is used for expressions
|
||||
that will throw an exception that we are planning to catch. This
|
||||
run function is used to discard the value of e.
|
||||
*)
|
||||
let run e = (fun x -> ()) e
|
||||
|
||||
|
||||
(* The subsetsum function that raises an exception on finding a
|
||||
solution.
|
||||
*)
|
||||
let subsetsum_exn_on_found (lst: int list) : int list option =
|
||||
let rec try_subset partial_subset rest_of_the_set =
|
||||
if sum partial_subset = 0 && partial_subset <> [] && rest_of_the_set = []
|
||||
then raise (FoundSubSet partial_subset)
|
||||
else match rest_of_the_set with
|
||||
| [] -> None
|
||||
| x::xs -> run (try_subset (partial_subset @ [x]) xs) ;
|
||||
try_subset partial_subset xs
|
||||
|
||||
in try try_subset [] lst with
|
||||
| FoundSubSet (result) -> Some result
|
||||
|
||||
|
||||
|
||||
(* Another, and better, way to use exceptions in searching is to raise
|
||||
an exception when we the search process has reached a deadend or
|
||||
the found solution is not acceptable.
|
||||
|
||||
In both cases we want to keep looking. Thus we create a
|
||||
"KeepLooking" exception.
|
||||
*)
|
||||
exception KeepLooking
|
||||
|
||||
|
||||
(* In this example, we raise an exception when we reach a deadend in
|
||||
the search process. This exception is caught in one of two places.
|
||||
|
||||
The first is at the point where there are more possibilities to
|
||||
explore, and thus another call to try_subset is made.
|
||||
|
||||
The second is at the point where there are no more possibilities
|
||||
and thus we catch teh exeption and return None.
|
||||
*)
|
||||
|
||||
let subsetsum_exn_not_found (lst: int list) : int list option =
|
||||
let rec try_subset partial_subset rest_of_the_set =
|
||||
if sum partial_subset = 0 && partial_subset <> [] && rest_of_the_set = []
|
||||
then Some partial_subset
|
||||
else match rest_of_the_set with
|
||||
| [] -> raise KeepLooking
|
||||
| x::xs -> try try_subset (partial_subset @ [x]) xs with
|
||||
| KeepLooking -> try_subset partial_subset xs
|
||||
|
||||
in try try_subset [] lst with
|
||||
| KeepLooking -> None
|
||||
|
||||
|
||||
(* In this example we again raise an exception to indicate that the
|
||||
search process should keep looking for more solutions, but now we
|
||||
use a version of the procss_solution function from above to have
|
||||
some process (the user) that can reject found solutions causing the
|
||||
function to keep searching.
|
||||
*)
|
||||
|
||||
let rec process_solution_exn show s =
|
||||
print_endline ( "Here is a solution:\n" ^ show s) ;
|
||||
print_endline ("Do you like it?") ;
|
||||
|
||||
match is_elem 'Y' (explode (String.capitalize (read_line ()))) with
|
||||
| true -> print_endline "Thanks for playing..." ; Some s
|
||||
| false -> raise KeepLooking
|
||||
|
||||
|
||||
(* This version of subsetsum is similar to subset_sum_option in that
|
||||
it uses a version of process_solution to keep looking for more
|
||||
solutions.
|
||||
*)
|
||||
let subsetsum_exn (lst: int list) : int list option =
|
||||
let rec try_subset partial_subset rest_of_the_set =
|
||||
if sum partial_subset = 0 && partial_subset <> [] && rest_of_the_set = []
|
||||
then process_solution_exn (show_list string_of_int) partial_subset
|
||||
else match rest_of_the_set with
|
||||
| [] -> raise KeepLooking
|
||||
| x::xs -> try try_subset (partial_subset @ [x]) xs with
|
||||
| KeepLooking -> try_subset partial_subset xs
|
||||
|
||||
in try try_subset [] lst with
|
||||
| KeepLooking -> None
|
||||
|
||||
|
||||
|
||||
(* We can abstract the subsetsub problem a bit more by parameterizing
|
||||
by the function that is called when a candidate solution is found.
|
||||
|
||||
The function passed in is sometimes referred to as a "continuation"
|
||||
as it indicates what the function should do, that is, how
|
||||
processing should continue, after it has completed its work.
|
||||
*)
|
||||
|
||||
|
||||
let subsetsum_exn_continutation
|
||||
(lst: int list) (success: int list -> int list option)
|
||||
: int list option =
|
||||
let rec try_subset partial_subset rest_of_the_set =
|
||||
if sum partial_subset = 0 && partial_subset <> [] && rest_of_the_set = []
|
||||
then success partial_subset
|
||||
else match rest_of_the_set with
|
||||
| [] -> raise KeepLooking
|
||||
| x::xs -> try try_subset (partial_subset @ [x]) xs with
|
||||
| KeepLooking -> try_subset partial_subset xs
|
||||
|
||||
in try try_subset [] lst with
|
||||
| KeepLooking -> None
|
||||
|
||||
(* The function below has the same behavior as subsetsum_exn, but we
|
||||
pass in process_solution_exn as an argument instead of writing it
|
||||
explicitly in the body of the subsetsum function.
|
||||
*)
|
||||
let subsetsum_exn_v1 lst =
|
||||
subsetsum_exn_continutation lst (process_solution_exn (show_list string_of_int))
|
||||
|
||||
(* This function has the same behavior as our original subsetsum
|
||||
function that accepts the first solution. Here the continuation
|
||||
function just wraps the result in a Some so that it can be
|
||||
returned.
|
||||
*)
|
||||
let subsetsum_exn_first lst =
|
||||
subsetsum_exn_continutation lst (fun x -> Some x)
|
||||
|
||||
let subsetsum_exn_print_all lst =
|
||||
subsetsum_exn_continutation
|
||||
lst
|
||||
(fun s -> print_endline ("Here you go: " ^ (show_list string_of_int s)) ;
|
||||
raise KeepLooking )
|
||||
|
||||
let results = ref [ ]
|
||||
|
||||
let subsetsum_exn_save_all lst =
|
||||
subsetsum_exn_continutation
|
||||
lst
|
||||
(fun x -> results := x :: !results ;
|
||||
print_endline (show_list (string_of_int) x) ;
|
||||
raise KeepLooking)
|
||||
|
||||
|
||||
|
||||
|
170
public-class-repo/SamplePrograms/Sec_01_1:25pm/search_options.ml
Normal file
170
public-class-repo/SamplePrograms/Sec_01_1:25pm/search_options.ml
Normal file
|
@ -0,0 +1,170 @@
|
|||
(* NOTE: This file will be updated as the lectures cover more search
|
||||
techniques. It is NOT COMPLETE as it now stands.
|
||||
|
||||
Below are the functions developed in lecture for the unit on search
|
||||
as a programmin technique. The slides are S6_Search.
|
||||
*)
|
||||
|
||||
(* Below, we generate all possible subsets of a set of values.
|
||||
Note that we are using lists to represent sets and simply
|
||||
assume that we do not have duplicates. If this is a concern
|
||||
we could use a "dedup" function to remove duplicates.
|
||||
|
||||
The important point here is to see that for each element in the
|
||||
list we have to make a choice - include it in the subset or do not
|
||||
include it.
|
||||
|
||||
This leads to the two recursive calls, one that returns subsets
|
||||
with it, and one that returns subsets without it.
|
||||
|
||||
See how the search tree we drew on the whiteboard corresponds to
|
||||
the "call graph" of the functions?
|
||||
*)
|
||||
|
||||
let gen_subsets lst
|
||||
= let rec helper partial_subset rest
|
||||
= match rest with
|
||||
| [] -> [ partial_subset ]
|
||||
| x::xs -> (helper (x :: partial_subset) xs)
|
||||
@
|
||||
(helper partial_subset xs)
|
||||
in helper [] lst
|
||||
|
||||
(* using List.map, courtesy of Tiannan Zhou *)
|
||||
let rec gen_subset' lst =
|
||||
match lst with
|
||||
| x::rest ->
|
||||
(
|
||||
let have_one = List.map (fun a -> x::a) (gen_subset' rest) in
|
||||
let not_have_one = gen_subset' rest in
|
||||
not_have_one @ have_one
|
||||
)
|
||||
| [ ] -> [[ ]]
|
||||
|
||||
|
||||
(* ---
|
||||
Options
|
||||
---
|
||||
*)
|
||||
|
||||
let s = [ 1; 3; -2; 5; -6 ] (* sample set from the S6 slides *)
|
||||
|
||||
let sum lst = List.fold_left (+) 0 lst
|
||||
|
||||
(* Our first implementation of subsetsum uses options to indicate if
|
||||
we found a solution or not. If our searching function 'try_subset'
|
||||
fails to find a value, it returns None; if it finds what we are
|
||||
looking for, then it returns that values wrapped up in a Some.
|
||||
*)
|
||||
let subsetsum_v1 (lst : 'a list) : 'a list option
|
||||
= let rec helper partial_subset rest
|
||||
= if sum partial_subset = 0 && partial_subset <> []
|
||||
then Some partial_subset
|
||||
else
|
||||
match rest with
|
||||
| [] -> None
|
||||
| x::xs -> match (helper (x :: partial_subset) xs) ,
|
||||
(helper partial_subset xs) with
|
||||
| Some solution, _ | (_, Some solution) -> Some solution
|
||||
| None, None -> None
|
||||
in helper [] lst
|
||||
|
||||
(* Here is another implementation of the above algorithm using
|
||||
options. The final value returned by the function is an int list,
|
||||
however. The empty list indicating that no subset was found.
|
||||
|
||||
The reason for writing this function is only to make it clear that
|
||||
using an option in the return type of the subsetsum function above
|
||||
was not related to our use of options in the recursive search
|
||||
procedure.
|
||||
*)
|
||||
let subsetsum_option_v2 (lst: int list) : int list =
|
||||
let rec try_subset partial_subset rest_of_the_set =
|
||||
if sum partial_subset = 0 && partial_subset <> [] && rest_of_the_set = []
|
||||
then Some partial_subset
|
||||
else match rest_of_the_set with
|
||||
| [] -> None
|
||||
| x::xs -> match try_subset (partial_subset @ [x]) xs with
|
||||
| None -> try_subset partial_subset xs
|
||||
| Some result -> Some result
|
||||
|
||||
in match try_subset [] lst with
|
||||
| None -> []
|
||||
| Some result -> result
|
||||
|
||||
|
||||
|
||||
(* Below we see how we can keep searching once we've found a solution to
|
||||
the problem.
|
||||
It may be that this solution is not acceptable to the user or there
|
||||
is simply some other evaluation criteria that we with to apply to
|
||||
the found solution.
|
||||
This lets the program keep looking even after finding a solution.
|
||||
*)
|
||||
|
||||
(* First, a function for converting lists into strings *)
|
||||
let show_list show l =
|
||||
let rec sl l =
|
||||
match l with
|
||||
| [] -> ""
|
||||
| [x] -> show x
|
||||
| x::xs -> show x ^ "; " ^ sl xs
|
||||
in "[ " ^ sl l ^ " ]"
|
||||
|
||||
(* Now, is_elem which is used in processing the solution *)
|
||||
let is_elem v l =
|
||||
List.fold_right (fun x in_rest -> if x = v then true else in_rest) l false
|
||||
|
||||
let rec explode = function
|
||||
| "" -> []
|
||||
| s -> String.get s 0 :: explode (String.sub s 1 ((String.length s) - 1))
|
||||
|
||||
let rec implode = function
|
||||
| [] -> ""
|
||||
| c::cs -> String.make 1 c ^ implode cs
|
||||
|
||||
(* We need to learn about modules soon ... S7 coming soon. *)
|
||||
|
||||
|
||||
|
||||
(* This function processes a solution, letting the user decide if
|
||||
the solution is acceptable or not.
|
||||
|
||||
If not, then we want to keep looking. Thus, it returns None,
|
||||
indicating that we have not yet found a solution, at least not one
|
||||
that we want to keep.
|
||||
|
||||
If it is acceptable, then Some s (the proposed solution) is returned.
|
||||
|
||||
The function also takes a show function to print out the solution
|
||||
to the user.
|
||||
*)
|
||||
let rec process_solution_option show s =
|
||||
print_endline ("Here is a solution: " ^ show s) ;
|
||||
print_endline ("Do you like it ?" ) ;
|
||||
match is_elem 'Y' (explode (String.capitalize (read_line ()))) with
|
||||
| true -> print_endline "Thanks for playing..." ; Some s
|
||||
| false -> None
|
||||
|
||||
(* This version of subsetsum will let the user choose from the
|
||||
discovered solutions, one at a time, until an acceptable one is
|
||||
found.
|
||||
|
||||
The process_solution_optoin function returns None of a Some value
|
||||
to indicate that the search should continue or end.
|
||||
*)
|
||||
let subsetsum_option (lst: int list) : int list option =
|
||||
let rec try_subset partial_subset rest_of_the_set =
|
||||
if sum partial_subset = 0 && partial_subset <> [] && rest_of_the_set = []
|
||||
then (* Instead of returning Some partial_subset and quitting we let
|
||||
the user decide to keep looking for more solutions or not. *)
|
||||
process_solution_option (show_list string_of_int) partial_subset
|
||||
else match rest_of_the_set with
|
||||
| [] -> None
|
||||
| x::xs -> match try_subset (partial_subset @ [x]) xs with
|
||||
| None -> try_subset partial_subset xs
|
||||
| Some result -> Some result
|
||||
|
||||
in try_subset [] lst
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
(* This is the filter function we wrote in class.
|
||||
|
||||
It differs a bit from the one in the file "streams.ml".
|
||||
*)
|
||||
|
||||
let rec filter (f: 'a -> bool) (s: 'a stream) : 'a stream =
|
||||
match s with
|
||||
| Cons (h, t) -> if f h then Cons (h, (fun () -> filter f (t ())))
|
||||
else filter f (t ())
|
114
public-class-repo/SamplePrograms/Sec_01_1:25pm/subsetsum_cps.ml
Normal file
114
public-class-repo/SamplePrograms/Sec_01_1:25pm/subsetsum_cps.ml
Normal file
|
@ -0,0 +1,114 @@
|
|||
(* ---
|
||||
Continuation Passing Style
|
||||
---
|
||||
*)
|
||||
|
||||
|
||||
let rec explode = function
|
||||
| "" -> []
|
||||
| s -> String.get s 0 :: explode (String.sub s 1 ((String.length s) - 1))
|
||||
|
||||
|
||||
(* First, a function for converting lists into strings *)
|
||||
let show_list show l =
|
||||
let rec sl l =
|
||||
match l with
|
||||
| [] -> ""
|
||||
| [x] -> show x
|
||||
| x::xs -> show x ^ "; " ^ sl xs
|
||||
in "[ " ^ sl l ^ " ]"
|
||||
|
||||
(* Now is_elem which are used in processing the solution *)
|
||||
|
||||
let is_elem v l =
|
||||
List.fold_right (fun x in_rest -> if x = v then true else in_rest) l false
|
||||
|
||||
(* We use a sum function below, so we'll bring in the needed functions
|
||||
for that. *)
|
||||
|
||||
let sum xs = List.fold_left (+) 0 xs
|
||||
|
||||
|
||||
|
||||
(* Continuation passing style is a style of writing programs in which
|
||||
the computation that happens after a function returns is packaged
|
||||
as a function and passed to that function instead where it is
|
||||
called directly.
|
||||
|
||||
In CPS, functions do not return. The computation that happens next
|
||||
is passed along as an argument in the form of a continuation
|
||||
function.
|
||||
|
||||
In the subsetsum problem we pass two continuations, one to evaluate
|
||||
if we succeed and find a subset that sums to 0, and another one in
|
||||
the case in which we fail and reach a deadend in the search
|
||||
process.
|
||||
*)
|
||||
|
||||
let rec process_solution_cps_v1 show s succ fail =
|
||||
print_endline ("Here is a solution: \n" ^ show s) ;
|
||||
print_endline ("Do you like it?");
|
||||
|
||||
match is_elem 'Y' (explode (String.capitalize (read_line ()))) with
|
||||
| true -> succ ()
|
||||
| false -> fail ()
|
||||
|
||||
let rec try_subset_cps_v1 partial_subset rest_of_the_set succ fail =
|
||||
if sum partial_subset = 0 && partial_subset <> [] && rest_of_the_set = []
|
||||
|
||||
then process_solution_cps_v1 (show_list string_of_int)
|
||||
partial_subset succ fail
|
||||
|
||||
else match rest_of_the_set with
|
||||
| [] -> fail ()
|
||||
| x::xs ->
|
||||
try_subset_cps_v1
|
||||
(partial_subset @ [x]) xs
|
||||
succ
|
||||
(fun () -> try_subset_cps_v1 partial_subset xs succ fail)
|
||||
(* Here the failure continuation will try to other
|
||||
possibility of not including x in the partial subset.*)
|
||||
|
||||
let subsetsum_cps_v1 (lst: int list) =
|
||||
try_subset_cps_v1
|
||||
[] lst
|
||||
(* Our success and failure continuations just print a message. *)
|
||||
(fun () -> print_endline "Yeah, we found one")
|
||||
(fun () -> print_endline "Oh no, no subset found.")
|
||||
|
||||
|
||||
|
||||
(* Another version in which the success continuation takes the chosen
|
||||
subset as an argument.
|
||||
*)
|
||||
|
||||
let rec process_solution_cps_v2 show s succ fail =
|
||||
print_endline ( "Here is a solution:\n" ^ show s) ;
|
||||
print_endline ("Do you like it?") ;
|
||||
|
||||
match is_elem 'Y' (explode (String.capitalize (read_line ()))) with
|
||||
| true -> succ s
|
||||
| false -> fail ()
|
||||
|
||||
|
||||
let rec try_subset_cps_v2 partial_subset rest_of_the_set succ fail =
|
||||
if sum partial_subset = 0 && partial_subset <> [] && rest_of_the_set = []
|
||||
|
||||
then process_solution_cps_v2 (show_list string_of_int)
|
||||
partial_subset succ fail
|
||||
|
||||
else match rest_of_the_set with
|
||||
| [] -> fail ()
|
||||
| x::xs ->
|
||||
try_subset_cps_v2
|
||||
(partial_subset @ [x]) xs
|
||||
succ
|
||||
(fun () -> try_subset_cps_v2 partial_subset xs succ fail)
|
||||
|
||||
let subsetsum_cps_v2 (lst: int list) =
|
||||
try_subset_cps_v2
|
||||
[] lst
|
||||
(fun ss -> print_endline ("Yeah, we found one.\n" ^
|
||||
"It is as folows:\n" ^
|
||||
show_list string_of_int ss))
|
||||
(fun () -> print_endline "Oh no, no subset found.")
|
182
public-class-repo/SamplePrograms/Sec_01_1:25pm/tail.ml
Normal file
182
public-class-repo/SamplePrograms/Sec_01_1:25pm/tail.ml
Normal file
|
@ -0,0 +1,182 @@
|
|||
(* Some functions used in S4.3 Improving Performance
|
||||
|
||||
Some of this material comes from section 9.4 of Chris Reade's book
|
||||
``Elements of Functional Programming''. This is in the `Resources`
|
||||
directory of the public class repository.
|
||||
|
||||
Some were written by Charlie Harper.
|
||||
|
||||
*)
|
||||
|
||||
|
||||
let rec listof n =
|
||||
match n with
|
||||
| 0 -> []
|
||||
| _ -> n :: listof (n-1)
|
||||
|
||||
let rec append l1 l2 =
|
||||
match l1 with
|
||||
| [] -> l2
|
||||
| x::xs -> x :: (append xs l2)
|
||||
|
||||
|
||||
|
||||
(* Problem 1: what is wrong with this function? *)
|
||||
let rec rev lst =
|
||||
match lst with
|
||||
| [] -> []
|
||||
| x::xs -> append (rev xs) [x]
|
||||
|
||||
|
||||
|
||||
|
||||
(* Problem 2: how can these be improved? *)
|
||||
let rec length lst = match lst with
|
||||
| [] -> 0
|
||||
| _::xs -> 1 + length xs
|
||||
|
||||
let rec sumlist lst = match lst with
|
||||
| [] -> 0
|
||||
| x::xs -> x + sumlist xs
|
||||
|
||||
|
||||
(*- stacking up the additions
|
||||
|
||||
Evaluation - if delay additions a bit
|
||||
sumlist 1::2::3::[]
|
||||
1 + (sumlist 2::3::[])
|
||||
1 + (2 + (sumlist 3::[])
|
||||
1 + (2 + (3 + sumlist [])
|
||||
1 + (2 + (3 + 0))
|
||||
|
||||
|
||||
*)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(* Some solutions
|
||||
--------------
|
||||
*)
|
||||
|
||||
(* Use an accumulating parameter to convert reverse from
|
||||
quadradic to linear time. *)
|
||||
let rev_a lst =
|
||||
let rec revaccum lst accum =
|
||||
match lst with
|
||||
| [] -> accum
|
||||
| x::xs -> revaccum xs (x::accum)
|
||||
in
|
||||
revaccum lst []
|
||||
|
||||
(* Does the above function remind us of imperative programming?
|
||||
|
||||
accum = [] ;
|
||||
while lst <> [] do
|
||||
x::xs = lst
|
||||
|
||||
lst = xs
|
||||
accum = x::accum
|
||||
|
||||
*)
|
||||
|
||||
|
||||
let length_tr lst =
|
||||
let rec ltr lst accum =
|
||||
match lst with
|
||||
| [] -> accum
|
||||
| x::xs -> ltr xs (accum + 1)
|
||||
in
|
||||
ltr lst 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(* We can also avoid stacking up the additions by using
|
||||
an accumulating parameter. *)
|
||||
let sumlist_a lst =
|
||||
let rec accsum lst n =
|
||||
match lst with
|
||||
| [] -> n
|
||||
| x::xs -> accsum xs (n+x)
|
||||
in
|
||||
accsum lst 0
|
||||
|
||||
|
||||
(*
|
||||
We delayed the additions - so not really call by value
|
||||
sumlist_a [1;2;3]
|
||||
accsum [1;2;3] 0
|
||||
accsum [2;3] (0+1)
|
||||
accsum [3] ((0+1)+2)
|
||||
accsum [] (((0+1)+2)+3)
|
||||
(((0+1)+2)+3)
|
||||
|
||||
|
||||
|
||||
*)
|
||||
|
||||
|
||||
|
||||
|
||||
(* Exercise: what is the tail recurive version of length? *)
|
||||
|
||||
|
||||
|
||||
(* Fibonacci numbers *)
|
||||
let rec fib n = match n with
|
||||
| 0 -> 0
|
||||
| 1 -> 1
|
||||
| n -> fib (n-1) + fib (n-2)
|
||||
(* What is the tail recursive version of the fib function
|
||||
that uses accumulators to avoid all the recomputation?
|
||||
*)
|
||||
|
||||
let fib_tr n =
|
||||
let rec fib_acc a b n = match n with
|
||||
| 0 -> a
|
||||
| n -> fib_acc b (a+b) (n-1)
|
||||
in
|
||||
fib_acc 0 1 n
|
||||
|
||||
|
||||
(* Another exercise: how does this relate to the imperative
|
||||
version? *)
|
||||
|
||||
|
||||
(* Let's recall sumlist and sumlist_tr.
|
||||
|
||||
Haven't we seen this before? *)
|
||||
|
||||
|
||||
let rec foldl f v l =
|
||||
match l with
|
||||
| [] -> v
|
||||
| x::xs -> foldl f (f v x) xs
|
||||
|
||||
let sum_f xs = foldl (+) 0 xs
|
||||
|
||||
(*-
|
||||
foldl (+) 0 (1::2::3::[])
|
||||
foldl (+) (0+1) (2::3::[])
|
||||
foldl (+) 1 (2::3::[])
|
||||
foldl (+) (1+2) (3::[])
|
||||
foldl (+) 3 (3::[])
|
||||
foldl (+) (3+3) []
|
||||
foldl (+) 6 []
|
||||
6
|
||||
|
||||
Or without evaluating + so early
|
||||
foldl (+) 0 (1::2::3::[])
|
||||
foldl (+) (0+1) (2::3::[])
|
||||
foldl (+) ((0+1)+2) (3::[])
|
||||
foldl (+) (((0+1)+2)+3) []
|
||||
(((0+1)+2)+3)
|
||||
6
|
||||
*)
|
||||
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
(* More tail recurive tree functions.
|
||||
|
||||
These are from Charlie Harper and over a differnt type of tree.
|
||||
*)
|
||||
|
||||
type 'a tree = Leaf of 'a
|
||||
| Fork of 'a * 'a tree * 'a tree
|
||||
|
||||
let t1 = Leaf 5
|
||||
let t2 = Fork (3, Leaf 3, Fork (2,t1,t1))
|
||||
let t3 = Fork ("Hello", Leaf "World", Leaf "!")
|
||||
|
||||
let ident = (fun x -> x)
|
||||
|
||||
let t_size t =
|
||||
let rec t_size_rec t k =
|
||||
match t with
|
||||
| Leaf _ -> k 1
|
||||
| Fork (_,tl,tr) ->
|
||||
t_size_rec tl (fun l ->
|
||||
t_size_rec tr (fun r ->
|
||||
k (1 + l + r) ))
|
||||
in
|
||||
t_size_rec t ident
|
||||
|
||||
let t_sum t =
|
||||
let rec t_sum_rec t k =
|
||||
match t with
|
||||
| Leaf v -> k v
|
||||
| Fork (v,tl,tr) ->
|
||||
t_sum_rec tl (fun l ->
|
||||
t_sum_rec tr (fun r ->
|
||||
k (v + l + r) ))
|
||||
in
|
||||
t_sum_rec t ident
|
||||
|
||||
let t_charcount t =
|
||||
let rec t_charcount_rec t k =
|
||||
match t with
|
||||
| Leaf v -> k (String.length v)
|
||||
| Fork (v,tl,tr) ->
|
||||
t_charcount_rec tl (fun l ->
|
||||
t_charcount_rec tr (fun r ->
|
||||
k (l + r + String.length v) ))
|
||||
in
|
||||
t_charcount_rec t ident
|
||||
|
||||
let t_concat t =
|
||||
let rec t_concat_rec t k =
|
||||
match t with
|
||||
| Leaf v -> k v
|
||||
| Fork (v,tl,tr) ->
|
||||
t_concat_rec tl (fun l ->
|
||||
t_concat_rec tr (fun r ->
|
||||
k (v ^ l ^ r) ))
|
||||
in
|
||||
t_concat_rec t ident
|
||||
|
||||
|
||||
let t_elem_by (eq: 'a -> 'b -> bool) (elem: 'b) (t: 'a tree) : bool =
|
||||
let rec t_elem_by_rec t k =
|
||||
match t with
|
||||
| Leaf v when eq v elem -> true
|
||||
| Fork (v,_,_) when eq v elem -> true
|
||||
| Leaf v -> k ()
|
||||
| Fork (v,tl,tr) ->
|
||||
t_elem_by_rec tl (fun u ->
|
||||
t_elem_by_rec tr k)
|
||||
in
|
||||
t_elem_by_rec t (fun u -> false)
|
||||
|
||||
(* The ordering is left then fork value then right *)
|
||||
(* t_to_list (Fork(1,Leaf 2,Leaf 3)) -> [2;1;3] *)
|
||||
let t_to_list (t: 'a tree) : 'a list =
|
||||
let rec t_to_list_rec t r k =
|
||||
match t with
|
||||
| Leaf v -> k (v::r)
|
||||
| Fork (v,tl,tr) ->
|
||||
t_to_list_rec tr r (fun r1 ->
|
||||
t_to_list_rec tl (v::r1) k)
|
||||
in
|
||||
t_to_list_rec t [] ident
|
||||
|
||||
let tfold (l:'a -> 'b) (f:'a -> 'b -> 'b -> 'b) (t:'a tree) : 'b =
|
||||
let rec tfold_rec t k =
|
||||
match t with
|
||||
| Leaf v -> k (l v)
|
||||
| Fork (v,tl,tr) ->
|
||||
tfold_rec tl (fun l ->
|
||||
tfold_rec tr (fun r ->
|
||||
k (f v l r) ))
|
||||
in
|
||||
tfold_rec t ident
|
||||
|
||||
(* A version of t_to_list that places the fork value first... *)
|
||||
(* t_to_list (Fork(1,Leaf 2,Leaf 3)) -> [1;2;3] *)
|
||||
let t_to_list_ff (t: 'a tree) : 'a list =
|
||||
let rec t_to_list_rec t r k =
|
||||
match t with
|
||||
| Leaf v -> k (v::r)
|
||||
| Fork (v,tl,tr) ->
|
||||
t_to_list_rec tr r (fun r1 ->
|
||||
t_to_list_rec tl r1 (fun r2 -> k (v::r2) ))
|
||||
in
|
||||
t_to_list_rec t [] ident
|
||||
|
||||
(* And a version that places the fork value last... *)
|
||||
(* t_to_list (Fork(1,Leaf 2,Leaf 3)) -> [2;3;1] *)
|
||||
let t_to_list_fl (t: 'a tree) : 'a list =
|
||||
let rec t_to_list_rec t r k =
|
||||
match t with
|
||||
| Leaf v -> k (v::r)
|
||||
| Fork (v,tl,tr) ->
|
||||
t_to_list_rec tr (v::r) (fun r1 ->
|
||||
t_to_list_rec tl r1 k)
|
||||
in
|
||||
t_to_list_rec t [] ident
|
175
public-class-repo/SamplePrograms/Sec_01_1:25pm/wolf.ml
Normal file
175
public-class-repo/SamplePrograms/Sec_01_1:25pm/wolf.ml
Normal file
|
@ -0,0 +1,175 @@
|
|||
(* Person, Wolf, Goat, Cabbage
|
||||
|
||||
Consider the problem of a person needing to move his wolf, goat,
|
||||
and cabbage across a river in his canoe, under the following
|
||||
restrictions:
|
||||
|
||||
- The canoe holds only the person and one of the wolf, goat, or
|
||||
cabbage.
|
||||
- The goat and cabbage cannot be left unattended or the goat will
|
||||
eat the cabbage.
|
||||
- The wolf and the goat cannot be left unattended or the wolf will
|
||||
eat the goat.
|
||||
- Only the person can operate the canoe.
|
||||
|
||||
Is there a sequence of moves in which the person can safely transport
|
||||
all across the river with nothing being eaten?
|
||||
*)
|
||||
|
||||
|
||||
let rec is_not_elem set v =
|
||||
match set with
|
||||
| [] -> true
|
||||
| s::ss -> if s = v then false else is_not_elem ss v
|
||||
|
||||
let run e = (fun x -> ()) e
|
||||
|
||||
let is_elem v l =
|
||||
List.fold_right (fun x in_rest -> if x = v then true else in_rest) l false
|
||||
|
||||
let rec explode = function
|
||||
| "" -> []
|
||||
| s -> String.get s 0 :: explode (String.sub s 1 ((String.length s) - 1))
|
||||
|
||||
|
||||
(* Types and functions for the crossing challenge. *)
|
||||
|
||||
(* Location: things are on the left (L) or right (R) side of the river. *)
|
||||
type loc = L | R
|
||||
|
||||
|
||||
(* A state in our search space is a configuration describing on which
|
||||
side of the river the person, wolf, goat, and cabbage are. *)
|
||||
type state = loc * loc * loc * loc
|
||||
|
||||
(* A state is safe, or OK, when the goat and cabbage are together only
|
||||
when the person is also on the same side of the river and when the
|
||||
wolf and the goat are together only when person is on the same side of
|
||||
the river.
|
||||
*)
|
||||
let ok_state ( (p,w,g,c) :state) : bool
|
||||
= p=g || (g <> c && g <> w)
|
||||
|
||||
|
||||
(* The final state, or gaol state, is when everything is on the right (R)
|
||||
side of the river.
|
||||
*)
|
||||
let final s = s = (R,R,R,R)
|
||||
|
||||
let other_side = function
|
||||
| L -> R
|
||||
| R -> L
|
||||
|
||||
let moves (s:state) : state list =
|
||||
let move_person (p,w,g,c) = [ ( other_side p, w, g, c ) ]
|
||||
in
|
||||
let move_wolf (p,w,g,c) = if p = w
|
||||
then [ ( other_side p, other_side w, g, c ) ]
|
||||
else [ ]
|
||||
in
|
||||
let move_goat (p,w,g,c) = if p = g
|
||||
then [ ( other_side p, w, other_side g, c ) ]
|
||||
else [ ]
|
||||
in
|
||||
let move_cabbage (p,w,g,c) = if p = c
|
||||
then [ ( other_side p, w, g, other_side c ) ]
|
||||
else [ ]
|
||||
in List.filter ok_state ( move_person s @ move_wolf s @ move_goat s @ move_cabbage s )
|
||||
|
||||
(* A solution using options that returns the first safe sequence of moves. *)
|
||||
let crossing_v1 () =
|
||||
let rec go_from state path =
|
||||
if final state
|
||||
then Some path
|
||||
else
|
||||
match List.filter (is_not_elem path) (moves state) with
|
||||
| [] -> None
|
||||
| [a] -> (go_from a (path @ [a]) )
|
||||
| [a;b] ->
|
||||
(match go_from a (path @ [a]) with
|
||||
| Some path' -> Some path'
|
||||
| None -> go_from b (path @ [b])
|
||||
)
|
||||
| _ -> raise (Failure ("No way to move 3 things!"))
|
||||
in go_from (L,L,L,L) [ (L,L,L,L) ]
|
||||
|
||||
|
||||
|
||||
(* Here is a solution that raises an exception when we've found a safe
|
||||
sequence of moves. It then stops.
|
||||
*)
|
||||
exception FoundPath of (loc * loc * loc * loc) list
|
||||
|
||||
let crossing_v2 () =
|
||||
let rec go_from state path =
|
||||
if final state
|
||||
then raise (FoundPath path)
|
||||
else
|
||||
match List.filter (is_not_elem path) (moves state) with
|
||||
| [] -> None
|
||||
| [a] -> (go_from a (path @ [a]) )
|
||||
| [a;b] ->
|
||||
run (go_from a (path @ [a]) ) ;
|
||||
go_from b (path @ [b])
|
||||
| _ -> raise (Failure ("No way to move 3 things!"))
|
||||
|
||||
in try go_from (L,L,L,L) [ (L,L,L,L) ]
|
||||
with FoundPath path -> Some path
|
||||
|
||||
|
||||
|
||||
|
||||
(* A solution that allows use to keep looking for additional safe
|
||||
sequences of moves.
|
||||
*)
|
||||
|
||||
exception KeepLooking
|
||||
|
||||
(* This is the same process_solution_exn function from search.ml *)
|
||||
let rec process_solution_exn show s =
|
||||
print_endline ( "Here is a solution:\n" ^ show s) ;
|
||||
print_endline ("Do you like it?") ;
|
||||
|
||||
match is_elem 'Y' (explode (String.capitalize (read_line ()))) with
|
||||
| true -> print_endline "Thanks for playing..." ; Some s
|
||||
| false -> raise KeepLooking
|
||||
|
||||
|
||||
(* Some function for printint a sequence of moves. *)
|
||||
let show_list show l =
|
||||
let rec sl l =
|
||||
match l with
|
||||
| [] -> ""
|
||||
| [x] -> show x
|
||||
| x::xs -> show x ^ "; " ^ sl xs
|
||||
in "[ " ^ sl l ^ " ]"
|
||||
|
||||
let show_loc = function
|
||||
| L -> "L"
|
||||
| R -> "R"
|
||||
|
||||
let show_state (p,w,g,c) =
|
||||
"(" ^ show_loc p ^ ", " ^ show_loc w ^ ", " ^
|
||||
show_loc g ^ ", " ^ show_loc c ^ ")"
|
||||
|
||||
let show_path = show_list show_state
|
||||
|
||||
(* The solution that lets a user selected from all (2) safe paths. *)
|
||||
let crossing_v3 () =
|
||||
let rec go_from state path =
|
||||
if final state
|
||||
then process_solution_exn show_path path
|
||||
else
|
||||
match List.filter (is_not_elem path) (moves state) with
|
||||
| [] -> raise KeepLooking
|
||||
| [a] -> go_from a (path @ [a])
|
||||
| [a;b] ->
|
||||
(try go_from a (path @ [a]) with
|
||||
| KeepLooking -> go_from b (path @ [b])
|
||||
)
|
||||
| _ -> raise (Failure ("No way to move 3 things!"))
|
||||
|
||||
in try go_from (L,L,L,L) [ (L,L,L,L) ] with
|
||||
| KeepLooking -> None
|
||||
|
||||
|
20
public-class-repo/SamplePrograms/Sec_10_3:35pm/arithmetic.ml
Normal file
20
public-class-repo/SamplePrograms/Sec_10_3:35pm/arithmetic.ml
Normal file
|
@ -0,0 +1,20 @@
|
|||
type expr
|
||||
= Int of int
|
||||
| Add of expr * expr
|
||||
| Sub of expr * expr
|
||||
| Mul of expr * expr
|
||||
| Div of expr * expr
|
||||
|
||||
(* eval: expr -> int *)
|
||||
let rec eval = function
|
||||
| Int i -> i
|
||||
| Add (e1, e2) -> eval e1 + eval e2
|
||||
| Sub (e1, e2) -> eval e1 - eval e2
|
||||
| Mul (e1, e2) -> eval e1 * eval e2
|
||||
| Div (e1, e2) -> eval e1 / eval e2
|
||||
|
||||
(* 1 + 2 * 3 *)
|
||||
let e1 = Add (Int 1, Mul (Int 2, Int 3))
|
||||
let e2 = Sub (Int 10, Div (e1, Int 3))
|
||||
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
(* from Feb 13 *)
|
||||
|
||||
(* What are the pieces of the type definition above?
|
||||
|
||||
1. the name of the type constructor: tree
|
||||
|
||||
2. the arguments of the type constructor: 'a
|
||||
|
||||
3. the variants names: Leaf and Fork
|
||||
these are also called value constructors
|
||||
|
||||
4. the values associated with those names
|
||||
a. Leaf which holds a value of type 'a
|
||||
b. Fork which holds a value and two sub trees.
|
||||
|
||||
*)
|
||||
|
||||
(* tree is parametric polymorphic type *)
|
||||
type 'a tree = Leaf of 'a
|
||||
| Fork of 'a * 'a tree * 'a tree
|
||||
|
||||
let t1 = Leaf 5
|
||||
let t2 = Fork (3, Leaf 1, Fork (6, t1, t1) )
|
||||
let t3 = Fork ("Hello", Leaf "World", Leaf "!")
|
||||
|
||||
let rec tsize t =
|
||||
match t with
|
||||
| Leaf _ -> 1
|
||||
| Fork (_, t1, t2) -> 1 + tsize t1 + tsize t2
|
||||
|
||||
let rec tsum = function
|
||||
| Leaf v -> v
|
||||
| Fork (v, t1, t2) -> v + tsum t1 + tsum t2
|
||||
|
||||
let rec tsum' = fun t ->
|
||||
match t with
|
||||
| Leaf v -> v
|
||||
| Fork (v, t1, t2) -> v + tsum' t1 + tsum' t2
|
||||
|
||||
|
||||
let rec tmap (eq:'a -> 'b) (t:'a tree) : 'b tree =
|
||||
match t with
|
||||
| Leaf x -> Leaf (eq x)
|
||||
| Fork (x, t1, t2) -> Fork (eq x, tmap eq t1, tmap eq t2)
|
||||
|
||||
let rec tfold (l: 'a -> 'b) (f: 'a -> 'b -> 'b -> 'b) (t: 'a tree) : 'b =
|
||||
match t with
|
||||
| Leaf v -> l v
|
||||
| Fork (v, t1, t2) -> f v (tfold l f t1) (tfold l f t2)
|
||||
|
||||
(* For Wednesday, use tfold to
|
||||
1. write an identity function for trees
|
||||
2. compute the number of characters in a string tree, such as t3
|
||||
*)
|
||||
|
||||
(* inttree is a monomorphic type *)
|
||||
type inttree = ILeaf of int
|
||||
| IFork of int * inttree * inttree
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue