在上一篇文章中,我们介绍了高级语言的想法以及编译器作为这些语言和机器语言之间翻译的角色,这是处理器所理解的。高水平的思考意味着即使在我们程序的最小细节中也必须以抽象为变量或功能,更接近人类的思维方式。但是,正如我们将在本文中看到的那样,除了这些基本的摘要之外,还有许多其他语言,而不同的语言则提供了不同的子集。
编程语言是一种纯粹的人类创造,从某种意义上说,它反映了其创作者的心态。因此,毫不奇怪的是,根据计划的结构方式,有数百种(如果不是数千种)语言将大约十个不同的家庭分为十个不同的家庭。以线性方式思考程序与将其视为对一系列外部事件的回应。第一种类型中使用的语言对于具有清晰起步和结束的任务(例如明天的天气锻炼)优选。第二个抽象对于描述移动应用程序背后的工作更有用,您可以在屏幕上触摸各种元素。
有趣的是,关于编程语言的讨论表明,两者之间的许多差异纯粹是审美的。例如,要表达“变量x的值为5”,最好写“ x?=?5”(就像我们在java或c中所做的那样),“ x??:=?5”(就像我们所做的那样在pascal)还是“ x?–?5” (as we do in R)? These discussions are so heated that famous language designer Philip Wadler proposed a law that said that exponentially more time was spent discussing language syntax (the way in which concepts are translated into symbols) than semantics (the ideas behind what we write).
Throughout history, a multitude of programming languages have been developed for different purposes and depending on the technologies of each era, thus giving rise to a kind of Tower of Babel of computer programming. / Imange: Pixabay
Let’s go back to discussing the different abstractions each language family offers us. Although they can be classified in various different ways and in as much detail as we like, there are four main commonly accepted families or paradigms: imperative programming, object-oriented programming, functional languages and logic programming. The latter two usually come under the single heading of declarative programming.
Imperative and object-oriented languages
A program written in an imperative programming language is essentially a sequence of commands or orders (this is where it gets its name from) that are executed from start to finish. The most basic commands are to modify the value of a variable or call a function; i.e. the simplest abstractions we talked about in our last entry. Imperative programming languages add the following two elements to these basic orders:
Conditional statements: a way of redirecting the flow of the execution depending on a value or property. Example: if the name text box is empty (condition), display an error message (order).
Loops: a way of repeating a series of orders. Example: for every number from 1 to 10, display this number on the screen. We don’t need to know the number of repetitions beforehand. This can depend on another condition. For example, display the message “press Y or N” on the screen until the user presses Y or N. Given the simplicity of these abstractions, many languages in other families also provide them. As pure imperative programming languages, we can highlight Fortran (born in 1954), Basic (1964), Pascal (1970), C (1972), and Python (1990). One of the main advantages is that these abstractions are very close or easy to translate to machine language. This is why a large proportion of high-performance software continues to be written in this paradigm.
However, as programs have grown in size and complexity, there has been a need for new abstractions which put even more distance between the programmer and the virtual machine. The first ideas of object-oriented programming were introduced in the mid-1960s. By 1970, there were already programming languages, such as Simula or Smalltalk, made using solely this paradigm. However, it exploded in 1985 with the arrival of C++, becoming the leading paradigm. Almost every new “mainstream” language since then — such as Java, Ruby or C# — has been object-oriented.
The emergence of goal-oriented programming languages starts in 1985. / Image: OpenMind
The fundamental idea of this paradigm is that the code is articulated through many different objects (sometimes called actors) that work independently and communicate with each other. If we want to print a restaurant check, we will communicate with a “check object,” which we will tell what has been ordered. This object will independently calculate the total and communicate with another “printer object” to print the check. The greatest advantage of this paradigm is its modularity: different teams can work independently on different parts of a program, and they only need to agree on how these objects or actors will communicate with each other.
Most object-oriented languages introduce the concept of subtyping to this common idea. Subtyping is a way of taking a step back from the peculiarities of each object. The most commonly used example is that of animals: sometimes I need to communicate with a “dog object” or a “cat object”, but sometimes a “pet object” is enough. In object-orientated programming, we can say that a dog is a pet and we can use the first instead of the second, without any problem. For a more IT-related example: the “printer object” mentioned earlier could be a subtype of an “information-sending object” of which another subtype could be “email-sending object” that sends the check by email.
Declarative Programming Languajes
Giving orders to the computer is the opposite of trying to explain to the computer what you want to do and letting it find a way to give you the result. That is, at least, the philosophy behind declarative languages: to provide a high level of language where the programmer expresses the problem in itself, and not so much how the program runs. Traditionally, the disadvantage of these languages has been the speed — translating everything into a series of simple commands is a difficult task for the compiler. However this has been reduced considerably in recent decades.
Logic programming languages look at the world as a series of “facts” that are taken as true and a series of “rules” for inferring information from those facts. A clearer example is the following description of family relationships between fathers and sons:
> 亚历克斯是朱利安的儿子。
> Quique是Alex的儿子。
>朱利奥是亚历克斯的儿子。
如果“先生是Pepito先生,Pepito先生是Mr.?x先生,则说“ X先生是先生先生”的规则。用逻辑语言,我们现在可以提出诸如``朱利奥Quique的祖父吗?''之类的封闭问题。- 它会回答“不”。或者我们可以提出诸如“孙子的祖父朱利安(Julian)?”之类的公开问题。- 它将回答“孙子= Quique,孙子=朱莉奥”,因为这是“孙子”的两个值,它们具有肯定的答案。
这些语言在人工智能的第一波中非常受欢迎,因为它们被认为是信息及其规则的良好代表。Prolog于1972年出生,实际上是该范式纯粹状态的唯一幸存者,并且一直是研究的对象。目前,当需要像逻辑编程提供的规则系统一样,通常将其集成为以其他范式编写的程序的一部分。
功能性语言
声明性编程中的另一个主要家庭由功能性语言组成。早些时候,我们说卓越的抽象之一是为程序中的价值命名。在大多数语言中,当我们说“价值”时,我们的意思是一个数据,例如数字,一个人的信息等。在功能性语言中,变量和功能之间的障碍被模糊,我们可以像任何其他值一样操纵功能(即计算机的指令序列)。例如,让我们想象我们有一个人列表,并希望为每个人执行一项操作。在命令式语言中,我们必须为要执行的每个操作编写一个新循环。在功能编程中,我们有一个操作,可以接收另一个功能并在列表上的每个项目上执行它。这样可以防止我们每次都必须写一个循环。
功能编程源自Alonzo Church在1930年代描述的名为Lambda演算的计算机模型。LISP /图像:OpenMind
功能编程的历史可以追溯到计算机本身。它源自Alonzo Church于1930年代发明的名为Lambda演算的计算机模型。LISP是历史上第二种高级编程语言(1958年),是一种功能性语言。最近的例子包括Erlang(1986),Haskell(1990),Conchet(1995),F#(2005)和Clojure(2007)。此外,有一种将功能编程元素纳入现有语言的趋势,例如Java,或混合面向对象的和功能性编程,例如Scala(2004)或Swift(2014)。
特定于域的语言
您正在阅读的当前页面的HTML信息,可以通过浏览器的检查选项访问。图像:OpenMind
到目前为止,我们讨论过的所有语言都是通用的。这意味着一般而言,这些语言使我们能够表达我们可能拥有的任何计算需求。还有其他语言专注于解决特定领域(或域)中的问题,故意排除其他用途。例如,您现在正在阅读的网页以一种名为HTML的语言编写,仅专注于渲染带有可能链接到其他网页的文本和图像(如果您右键单击,可能会有一个“视图”代码”选项,向您显示HTML)。
信息系统的重要需求是咨询和修改数据库。在这里,我们找到了另一种特定领域的语言(SQL),旨在以最简洁的方式表达这些查询。最后,一个众所周知的例子是电子表格。每当我们在单元格中编写一个公式时,例如“ = sum(a1:a20)”,我们都会用一种数学公式的语言编写。
从外面看,“编写程序”似乎是以特定方式完成的。但是,正如我们已经看到的那样,在半个世纪的计算机科学中,已经创建了多种编程语言,为需要解决的问题提供了多种方法。
亚历杭德罗·塞拉诺(Alejandro Serrano Mena)