Folding is one of the most
useful tools in functional programming. You will certainly use it
many times over the course of the semester. The following exercises
are designed to get you comfortable with folding to do useful
computations on lists. Note: All of these functions can be written
without folding, but the point of the exercise is to get used to
folding, so every function must include either List.fold_left
or
List.fold_right
. Note that List.fold_left
is tail recursive
and List.fold_right
is not. For full credit, do not use the rec
keyword.
map : ('a -> 'b) -> 'a list -> 'b list
that
is an implementation of the List.map function using only List.fold_left
or List.fold_right.
map succ [1;2;3] = [2;3;4]
.
simple_stats : float list -> (float * float * float * float * int)
.
Given a list of floats, simple_stats
finds the min, max, mean, range,
and number of elements
in the list passed in (range is the difference between the min and the max).
For full credit, you are restricted to use only one list folding function,
and all of the work must be done inside of this function.
simple_stats [1.0;1.0;2.0;3.0;5.0;8.0;11.0] =
(1., 11., 4.4285714285714288, 10., 7)
hex_to_decimal : char list -> int
.
Given a hexadecimal number represented as a list of characters, it will convert the hexadecimal number into
a integer representing the hex number in decimal.
convert_hex_to_decimal ['2';'A'] = 42
InvalidCharacter
.
convert_hex_to_decimal ['K'] = Exception: InvalidCharacter "Invalid char".
mystery_base_addition : int list -> int list -> int -> int list
.
Given two lists of nonnegative integers in the range 0 to b-1, each representing the base-b digits of a number
from higher to lower significance, you must add the two numbers together.
mystery_base_addition [0;0;1] [0;0;1] 2 = [1;0]
mystery_base_addition [2;7] [1;5] 10 = [4;2]
.
InvalidNumber
.
mystery_base_addition [2;7] [1;5] 3 = Exception: InvalidNumber "Higher than base".
List.fold_left2
or List.fold_right2
.
You have been provided with three arrays. The instructionArray will be used to store the instructions that are loaded from a text file. This instructions will then be executed. The memoryArray will be used to represent the computer's main memory, and the registerArray will be used to represent the computer's register set. Both the memory and registers are being represented as string arrays, because in this problem set they will always store hexadecimal numbers.
Every processor has its own machine code instruction set. We will be using a very small and simplified subset of the assembly language instructions provided by the MIPS architecture. In general, you can expect to see the following things in a file containing MIPS assembly instructions:
lw $dest offset($base)
|
Load Word: loads the value found in memory location [$base + offset] into the register $dest. Here $base refers to the contents of register $base and offset is a decimal number. |
sw $source offset($base)
|
Store Word: stores the value found in register $source in memory location [$base + offset]. |
addi $dest $reg imm
|
Add Immediate: computes $reg + imm and stores it in $dest. Imm is a decimal number. |
add $dest $reg1 $reg2
|
Add: computes $reg1 + $reg2 and puts the result in $dest. The registers do not have to be different. |
sub $dest $reg1 $reg2
|
Sub: computes $reg1 - $reg2 and stores it in $dest. |
j label
|
Jump: jumps to the instruction specified by label. Note that the label declaration must have a colon (:), but references to it in jump instructions do not. |
jr $reg
|
Jump Register: jumps to the n-th instruction, where n is the
value stored $reg. e.g. if $r1 = "A", then jr $r1
jumps to the tenth instruction.
|
beq $reg1 $reg2 label
|
Branch on Equal: compares $reg1 and $reg2 for equality. If they are equal, then jump to the instruction specified by label. |
bne $reg1 $reg2 label
|
Branch on Not Equal: if $reg1 does not equal $reg2, then jump to the instruction specified by label. |
Working with arrays:
Using arrays in OCaml is very simple. To access an element, such as the second index in the registerArray, simply do the following:
registerArray.(2)
This always evaluates to a type equal to the type of the array (in this case, string).
Array elements are mutable (assignable). To mutate an element in an array, such as the third index in the memory array:
memoryArray.(3) <- "Some_Hexadecimal_Number"
This will always evaluate to a type unit.
Important Notes:
Your task:
create_instruction_list
. You have already been supplied with a function split_lines
that splits a line into a string list. For example, the line
lw $r1 12($r3) #Short comment
["lw"; "$r1"; "12"; "$r3"; "#Short"; "comment"]
It is your job to take the string list list given to you by
split_lines
and convert it into an instruction list. Remember that
all comments must be ignored, and you must raise a Failure when there is an
incorrectly formed or incorrectly named instruction.
populate_instruction_array
.run_program
. We have
provided you with a simple text file "mult.txt" that carries out multiplication
of two numbers. Entering the following two lines in the OCaml toplevel:
run_program "mult.txt";;
print_registers();;
Should give the following output:
Reg.0 Hex: 0 Dec: 0
Reg.1 Hex: 2A Dec: 42
Reg.2 Hex: 6 Dec: 6
Reg.3 Hex: 0 Dec: 0
Reg.4 Hex: 2A Dec: 42
Reg.5 Hex: 0 Dec: 0
Reg.6 Hex: 0 Dec: 0
Reg.7 Hex: 0 Dec: 0
If you look into the mult.txt file you will notice that not all of the nine assembly instructions are being used. This means that to fully test your implementations, you will have to write your own simple assembly instructions.
add
subroutine that works with the assembly language you have implemented. Demonstrate its operation
by adding 27 to 15. Specifications:
addi
calls. You may not use add
in your code.$r3
.run_program "add.txt"
.