Document directory
- Let-bind
- Reference: real variables
- Nested Functions
From: http://www.nirvanastudio.org/ocaml/the-structure-of-ocaml-programs.html
Original article address:Http://www.ocaml-tutorial.org/the_structure_of_ocaml_programsTranslation: ShiningRay
Now we will spend some time looking at the actual OCaml program at a higher level. I want to teach you how to use local and global definitions.;;
When is it;
And modules, nested functions, and references. In this way, we need to look at these OCaml concepts that we have never seen before, but now we don't have to worry about details. First, pay attention to the overall structure of the program and some features I have pointed out.
Local "variable "(
ActuallyLocal expressions)
Let's take it firstaverage
Take a look at the function and add a local variable in the C language (you can compare it with our first definition ).
double
average (double a, double b)
{
double sum = a + b;
return sum / 2;
}
Now we are doing the same thing in OCaml:
let average a b =
let sum = a +. b in
sum /. 2.0;;
# Let average a B = (a +. B)/. 2.0; pay attention to priority.
Val pjz: float-> float = <fun>
# Pjz 10.5 21.5 ;;
-: Float = 16.
#
Standard phraselet name = expression in
Can be used to define a local expression, and thenname
It can be used in subsequent functions to replaceexpression
Until the end of the code block;;
. Note thatin
We didn't indent it later. Just putlet...in
As a statement.
Now, compare the local variables of C with those named local expressions, as if they were similar. They are actually two different things. C variablesum
There is a slot assigned to it on the stack. If necessary, you can givesum
Assign value or even obtainsum
. However, this is not true for the OCaml version. In the OCaml version,sum
Only expressionsa +. b
. Not possiblesum
Assign a value or change its value. (I will show you how to create real variables later ).
The following is another example to make things clearer. The following two code snippets return the same value (that is, (a + B) + (a + B) 2 ):
let f a b =
(a +. b) +. (a +. b) ** 2.
;;
let f a b =
let x = a +. b in
x +. x ** 2.
;;
The second version may be faster (but now most compilers should be able to "remove duplicate subexpressions" for you) and easier to read. In the second examplex
Onlya +. b
.
Global "variable "(
ActuallyGlobal expression)
You can also define global names for some things at the top level. Like the local "variables" we mentioned above, these are not real variables, but just aliases of some things. The following is an example of a practical application (for deletion ):
Let html =
Let content = read_whole_file file in
GHtml.html _ from_string content
;;
Let menu_bold () =
Match bold_button # active
True-> html # set_font_style ~ Enable: ['bold] ()
| False-> html # set_font_style ~ Disable: ['bold] ()
;;
Let main () =
(* Code omitted *)
Factory # add_item "Cut "~ Key: _ X ~ Callback: html # cut
;;
In this actual code,html
Is an HTML editorial component (an object from the lablgtk Library), which is composed of the first line of statementslet html=
It is created at the beginning of the program. Then it is referenced multiple times in subsequent functions.
Note thathtml
The name cannot be regarded as an actual global variable in C or other imperative languages. There is nohtml
Pointer "allocates any space for" Storage ". Orhtml
Assign any value, for example, re-assign it to another different part. In the following section, we will discuss references, which are the real variables.
Let-bind
Anylet ...
Is calledLet-bind.
Reference: real variables
What if you need to assign values to a real variable that can be used and changed in the program? In this case, we need to useReference(Reference ). References are very similar to pointers in C/C ++. In Java, all the variables for saving objects are actually object references (pointers ). In Perl, references are references-the same thing as in OCaml.
The following describes how to createint
Worth referencing:
ref 0;;
In fact, this statement has no major purpose. We only created a reference, but because we didn't name it, the garbage collector will immediately recycle it! (In fact, it may also be thrown away during compilation ). Let's name this reference:
let my_ref = ref 0;;
# let myvar= ref "hello";;
val myvar : string ref = {contents = "hello"}
#
This reference currently stores an integer zero. Next we will put some other things in (assign values ):
my_ref := 100;;
At the same time, let's see what this reference contains:
# !my_ref;;
- : int = 100
Show variable value
# !myvar
;;
- : string = "hello"
#
So,:=
The operator is used to assign values to the reference.!
The operator can unreference and obtain the actual content. The following is a rough comparison with C/C ++:
OCaml C/C++
let my_ref = ref 0;; int a = 0; int *my_ptr = &a;
my_ref := 100;; *my_ptr = 100;
!my_ref *my_ptr
References have their purposes, but you may find that references are not often used. More often, you will uselet name = expression in
To name a local expression.
Nested Functions
C does not actually have the concept of nested functions. GCC supports nested functions of C Programs, but I still don't know what programs will actually use this extension. Anyway, let's first look at how the gcc info page explains nested functions:
A "nested function" refers to a function defined in another function. (Gnu c ++ does not support nested functions .) The name of a nested function is limited to the code block defined by it. For example, we define a nested function called square and call it twice:
foo (double a, double b)
{
double square (double z) { return z * z; }
return square (a) + square (b);
}
Nested functions can access any variables that can be seen when the functions that contain them are defined. This is called lexical scoping ). For example, the following shows how to use a nested function with inherited variables called 'offset:
bar (int *array, int offset, int size)
{
int access (int *array, int index)
{ return array[index + offset]; }
int i;
/* ... */
for (i = 0; i < size; i++)
/* ... */ access (array, i) /* ... */
}
You should understand. However, nested functions are very useful and commonly used in OCaml. The following is an example of nested functions captured from some practical application code:
let read_whole_channel chan =
let buf = Buffer.create 4096 in
let rec loop () =
let newline = input_line chan in
Buffer.add_string buf newline;
Buffer.add_char buf '\n';
loop ()
in
try
loop ()
with
End_of_file -> Buffer.contents buf;;
You don't need to worry about what this code has done-it also contains many concepts that have not been discussed in this tutorial. The first thing that follows is"loop
"Nested function, which has only one unit parameter. You can callread_whole_channel
Callingloop ()
But it is not defined outside the function. Nested functions can access the variables defined in the main function (hereloop
Accessible local namebuf
).
The form of nested functions is the same as that of local naming expressions:Let nameParameters=Function DefinitionIn
.
In general, you need to indent the function definition on the new line, as shown in the above example, and remember that if the function is recursive, you need to uselet rec
Ratherlet
(As shown in the preceding example ).