PROGRAMMING: WHAT YOU DO NOT NEED BUT USEFUL
KÁLMÁN LÁSZLÓ
2:25.
24 SCIENCE
They asked me, in fact, what my purpose is with this whole thing, what is good about programming at elementary level or even more dedusively to write when any programming language can be learned in many places, either with help or alone, much faster than when someone it reads my slow and unattractive flaws. It's true that I do not intend to let the reader get a quick success so that you can already write a program that is fun. I did not even choose a specific programming language for the reader. I do not strive to give an overview of many different "paradigm" ideas or technical solutions. Instead, I capture different details from the different possibilities of different languages because they are not really talking about the computer and the programs that can be run on it, but about the thinking of the programmer as he attempts to formulate his own non-informational thoughts with the utmost precision of automatically operating computer system can be built.
Those wonderful gadgets
So far, I have talked about everything that can not be circumvented, which is bound to be such a thought: it has to put algorithms into the form of the procedures and need to figure out a representation of your data. Today, however, it will be something that, in principle, would not be needed, is only useful in practice. How our program can be made up of very small modules that are largely independent of each other (and can therefore be replaced separately). There are plenty of programs that are not doing this and they can work well, but it's much harder to maintain, continue, share, share, or collaborate with others on their development than if they were written in a modular way.
Take the 52 card of the French card again. I've signaled it last time, but maybe not quite emphasized that there are countless ways to portray them in memory. Then I showed you how to look at the queue cards, the pacle to an array of 104 numbers, each pair of 2 * i numbers encrypts the color of the page number i, and the 2 * i + 1 element is the same page value. I could also have chosen that the colors and the page values are not numbered, but only a few bit sequences, since there are far few colors and values as many numbers. It could have been done by using two blocks of 52 elements, one in the i index with the color of the i, and the other in the same index with the same page value. And so on, there are all kinds of options. The point is, if you are programming in a modular way, you should not calculate which solution you choose when you want to do something with the card deck, then we do not have to know that at all. If another part of the program, say what modeling the players' decisions is written by someone else, then you do not have to look into the part where we have solved the pages and the deck.
The modules are black boxes from the outside, no matter what they are, but the point is how we can use them. This is what the outside world knows about them, with a term we call it interface (or interface as you like). What's in them is what they do not need to see from outside, they are called implementation and implementation .
The module is black box
I'll just say a simple example, a bit exaggerating, because I'm going to assume that even the representation of the colors of the card is wrapped in a small module, black box, but I would probably not put it into a separate module in reality. What should the outside world know about the colors of the card? Really not much, but it's useful, for example, to display some of the colors on the screen (for example, spell on the screen with a string that is pikk or that ♠). If you play a role in a card game (eg when it comes to a bridge), then we need to know what two colors are in each other's relationship (lower one with each other, and if so, which one is lower). We might want to do something else with the colors, but let's stay with these two things. The black box, the interface of our module, should include these services, for example, in the form of procedures: the outside world may ask for a module of our module to show (give back as a value) the representation of a certain color string or to decide (again by resetting some value) that there are two colors that relate to each other and so on. And last but not least, to start these processes, we have to be able to refer to colors at all, so there must be a data type, called a color whose details and representations do not have to be known to the outside world, but must be able to talk about these types of existence. The name of this data type belongs to the interface.
Now I will use a programming language as an example to show the best and easiest way to show OCaml, a descendant of the SML (Standard ML) language . In this language, the colors associated with the interface will include:
type color
This only means that there is a group (type, class) of the beings that is symbolically called color. Then:
print color: color -> string
This means that there must be a procedure (function), the only argument of which is a syntax type, a return value, and a string type. (It is obvious that OCaml is one of the languages that we used to call the functional language of the past.) The type of syntax is the range of interpretations, the string called the value set. Such a characterization of functions is called the signature or prototype of a function. (Anyway, the description of the whole interface is also called the signature of the module.) And then it is still:
similar to: syn * color -> int
This is also a sign of a function, only in this range of interpretations there are pairs of two types of things (marked by the "*" sign between the two types), the set of values is an integer. Of course, we need to explain why and how to mark the result of the comparison of two colors. This is a fairly general convention, and in fact there can only be three numbers: the number -1 is used to encode that the first element of the pair is smaller, the number 1 being the second element smaller, and the 0 being equal in size two elements.
In OCaml, interfaces are called module types , so they need to be specified:
module type SIN =
sig
(* Card color types: *)
type color
(* Assign color to color: *)
print color: color -> string
(* -1: first lower; 1: second; 0: same: *)
similar to: syn * color -> int
end
There are comments between "*" and "*), these are not part of the program, but are intended to explain the use of the interface to anyone who wants to use the module.
Of course, we could enrich this interface with everything else, for example, to allow the module to use the symbols to refer to the specific colors in the outside world:
(* The trump color (the lowest): *)
val treff: color
(* The curling color (after the treff): *)
val karo: color
And so on. These symbols are sometimes called constants , and if they are function mania, they can be regarded as a constant function, always returning the same value to that color.
The implementation can come!
And then let's go to what the module's internal affair is, how to portray the colors and how to define our two functions. So come up with a possible implementation and implementation of the above interface (module type, module signature). You can implement the same interface in several ways, even in the same program, so you need to name the implementations. (In fact, the reverse is true, there may be several interfaces for the same implementation.) In OCaml, the implementation is simply a module , its description is called a structure , so it will look like an implementation:
module Color: SZIN = struct (* ... *) end
The first line means that this implementation (module) will be the name of Sin, and we will declare that this module is an implementation of the module type (interface) called the SZIN. Then there will be definitions between the struct and the end.
The details of the implementation are no longer interesting for the current topic and the modularity, but for the sake of the order,
type syn = int
print with
fn 0 => "♣"
| 1 => "♢"
| 2 => "♡"
| _ => "♠"
similar to
fn (0, 0) => 0
| (0, _) => -1
| (1, 1) => 0
| (1, _) => -1
| (2, 2) => 0
| (2, _) => -1
| (3, 3) => 0
| (_, _) = 1
In the first line, we simply stated that the color type is the same as the integer type (but the outside world will not know). Then comes the definition of the two functions. Here, we have chosen an interesting format: after the keyword fn, the value of each argument is given one by one (after a "=>") return value of the function. The "_" sign must be read "anything else". So if the similar function argument is a (0, 0) ordered pair, then 0 is the value, and if the first element is 0, and the second is anything else (but not 0 since it was already), then -1 is the value (because the treff is the lowest color).
Homework
Home task (you do not have to submit solutions): write to the page values, then the interfaces and implementations for the pages. The whole module for the card deck can not yet be written in this language because it belongs to its interface such as mixing and assignment of the deck (which means that we create a smaller deck) and we can not find them based on the above how to implement it. But let the reader just think what he wants to see in the deck module interface.
For the sake of total truth, I have to say that there are many situations in which the modules are not so simple and there are many programming languages that have to be understood differently (for example, they have to grasp them as independent ones and have a place to memorize them). We need to prepare ourselves spiritually, but do not worry about the details for now.
To sum up: When we populate our universe, we must make sure that we do not make clutter. We put the related things in separate corners and carefully determine how the separate things can communicate with each other exactly. Although I am not clumsy, in fact, but I found that if there is no order in the virtual space, the terrible amount of extra work and time losses.