file: 01.2.typesExprsFuncsLibs.txt author: Bob Muller CS1103 Computer Science 1 Honors Boston College Lecture Notes Week 1, Meeting 2 Topics: 1. What is a Programming Language? 2. Basic Types, Constants and Expressions, Evaluation and Values 3. Naming Values 4. Libraries 5. Defining Functions 1. What is a Programming Language? For the purposes of this course, we can understand a language as a system for expressing ideas. A programming language is a language designed to express ideas related to computation and information. At the present time, most programming languages, including OCaml, are text-based: the program code in the language is written out in text (much like these notes) and is then processed by the computer to carry out the expressed computation. In OCaml, this processing is typically carried out by an -interpreter- which 1. READs: prompts the user for and reads an OCaml expression 2. EVALUTEs: evaluates the expression to find its value if it has one 3. PRINTs: print the value to the shell 4. LOOPs back to step 1. For example, an interaction with OCaml's evaluate shell might look like: # 3.14 *. 2.0;; - : float = 6.28 # NB: In the text above the hash-sign "#" is OCaml's prompt and the trailing ";;" is the user's signal to OCaml that we'd like the expression to be evaluated. Since the 3-step (read-eval-print) process is done over and over in a -loop-, the setup is sometimes called a REPL. ---------------- 2. Basic Types, Constants and Expressions, Simplification and Values In computing, -types- can be understood as sets of "things" that are the subject of the computation. All programming languages provide a number of basic types such as int and float that are built-in to the language. Most programming languages have ways to define new types. We'll get to that subject later. Virtually all programming languages have basic types int and float together with built-in operators (e.g., +, -, *, /, mod) that work on values of that type. The int Type # 2;; - : int = 2 2 is a -constant- expression of type int the -value- of a constant is itself # 5 * 2;; - : int = 10 10 is the -value- of the expression 5 * 2. CONVENTION: Operators should usually have spaces on either side So "5 / 2" is good, "5/2" is less good, and both "5 /2" and "5/ 2" are bad. Some coders prefer a style in which operators of lower precedence are surrounded by spaces while operators of higher precedence do not. For example, instead of a *. x +. b *. x +. c one might write: a*.x + b*.x + c Integer division # 5 / 2;; - : int = 2 # 1 / 2;; - : int = 0 # 5 mod 2;; - : int = 1 If we want both the quotient and the remainder, we can write: # let div m n = (m / n, m mod n);; val div : int -> int -> int * int = Division by 0 # 1 / 0;; Exception: Division_by_zero. The float Type # 3.14;; - : float = 3.14 # 314e-2;; - : float = 3.14 # 2.0 *. 3.14;; - : float = 6.28 # 5.0 /. 2.0;; - : float = 2.5 # 2.0 ** 3.0;; 2.0^3.0 - : float = 8. # infinity;; - : float = infinity # 1.0 /. 0.0;; - : float = infinity Type Conversion # float_of_int 1;; - : float = 1.0 # float 1;; - : float = 1.0 # int_of_float 3.14;; - : int = 3 Operators as Functions -- prefix notation # (+);; - : int -> int -> int = # ( * ) 2 3;; - : int = 6 # ( ** ) 2. 3.;; - : float = 8. The built-in operators are interpreted using the familiar PEMDAS order for the operators. Euclid's Common Notion #1: Things that are equal to the same thing are equal to each other. # 2.0 +. 3.14 *. 4.0;; = 2.0 +. 12.56 # These 2 lines for illustration = 14.56 - : float = 14.56 As usual, the normal order can be altered with parenthesization # (2.0 +. 3.14) *. 4.0;; 20.560000000000002 # NB: 15 decimal places of information Unit # ();; - : unit = () Characters # 'M';; - : char = 'M' # Char.code 'M';; - : int = 77 Strings # "hello world!";; - : string = "hello world!" # "hello" ^ " world!" - : string = "hello world!" Boolean (or Logical) Values There are just two values of this type, the constants true and false. # true;; - : bool = true # false;; - : bool = false # not true;; - : bool = false # false || true;; - : bool = true # true && false;; - : bool = false Summary: - OCaml's modus operandi is to simplify -expressions- in search of their values. Expressions are mostly familiar, being built-up from constants of base type, operators and parentheses. - Expressions can be evaluated by simplifying them to their values if they have one. - A -value- is an expression that cannot be further simplified. So for now, the containment is: +--------------------------+ | Expressions | | +----------------------+ | | | Values | | | | +------------------+ | | | | | Constants | | | | | +------------------+ | | | +----------------------+ | +--------------------------+ Every constant is a value and every value is an expression. There are expressions that are not values and (as we will see) there are values that are not constants. Later on we will alter this diagram a bit. ------------------- 3. Naming Values We can use the let-form: let variable = Expression to name the value of Expression. # let r = 3.14 *. 2.0;; - : float = 6.28 # let pi = acos(-1.0);; - : float = 3.14159265358979312 # yield a value but it does record # an association between PI and 3.14. # pi;; - : float = 3.14159265358979312 # pi *. 2.0;; - : float = 6.28318530717958623 ------------------- 4. Libraries Like most programming languages, OCaml has vast libraries of code that OCaml programmers can use off-the-shelf in writing their code. For the most part, this library code is packaged up as "modules" of functions that are grouped by their purpose. For example, there is a 'math' module with sin and cos functions, a 'random' module for working with random numbers. OCaml has a Standard Library that comes with all implementations of OCaml. See the web sites: http://caml.inria.fr/pub/docs/manual-ocaml/core.html and http://caml.inria.fr/pub/docs/manual-ocaml/stdlib.html But the world-wide OCaml community has developed many, many more, (many thousands) of library modules that provide functionality beyond the standard library. Accessing Library Modules Functions defined in Standard Library modules can be accessed by prefixing the function name with the module name. For example, # Random.int;; - : int -> int # Random.float;; - : float -> float # String.length;; - : string -> int = # List.length;; - : 'a list -> int = Note that the same function name (i.e., length) can be defined in more than one library module. Pervasives The definitions in OCaml's Pervasives library are imported automatically. Google "OCaml Pervasives" for a list. # abs(-3);; - : int = 3 # floor 3.999;; - : float = 3. ------------------- 5. Defining Functions 1. Functions are the main tool for packaging up computation in almost all programming languages. 2. Functions have -definitions- and -uses-. A function may or may not have -return- statements. 3. Function definitions are usually stored in a text file with the .ml extension. ----------------------------------- 1. A function definition has the form: let functionName var1 ... varn = expression The items var1, ..., varn are -variables-. In this position, they are called -formal parameters-. They may also occur in the expression which is called the -body- of the function definition. CONVENTION: function names and variable names start with a lower-case letter and are usually made up of works. For readability, the inner words start with a capitol letter as in: thisIsMyFunctionName or thisIsMyVariableName Or, sometimes the words are separated with underscores as in this_is_my_variable_name 2. A function -use-, -call- or -application- has the form: (functionName expr1 ... exprn) where each of expr1, ..., exprn is an -expression-. How does a defined function do its job? Well, the defined function is -called- in an attempt to simplify the call to a value. 1. When a function call is evaluated, for each i = 1,..,n, expri is evaluated. This process may produce a value Vi, it may encounter an error or it may not stop (more on that later). 2. If for each i, the evaluation of expri produces a value Vi, the value Vi is plugged-in for vari in the function body (i.e., each occurrences of vari is -replaced- by value Vi). 3. Then the body of the function is simplified and the value of the body of the function is the value of the call of the function. Example: a doubling function # let double x = x * 2;; val double : int -> int = # double(2 + 2);; -> double(4) -> 4 * 2 -> 8 # double(3) + double(2 + 3);; -> 3 * 2 + double(2 + 3) -> 6 + double(2 + 3) -> 6 + double(5) -> 6 + 5 * 2 -> 6 + 10 -> 16 Example: A min3 function that finds the minimum of 3 inputs. # let min3 p q r = min p (min q r);; val min : int -> int -> int -> int In OCaml (as in almost every other programming language!) computations are bundled up in functions!