Обычно, когда люди обсуждают «парадигму» языка программирования, они обсуждают, является ли это объектно-ориентированным программированием (ООП), функциональным программированием, процедурным программированием и т. д. Чтобы эффективно общаться, давайте определим, что будет означать «парадигма» в этом посте.
Парадигма. В науке и философии парадигма – это отдельный набор концепций или моделей мышления, включая теории, методы исследования, постулаты, стандарты и т. д., составляющие экзистенциальные взгляды. По сути, это мыслительный процесс, основанный на ваших экзистенциальных взглядах, и он определяет, как вы видите вещи, определяете их и понимаете мир.
Давайте также дадим определение «экзистенциальному».
Экзистенциальный: экзистенциализм — это форма философского исследования, которое исследует характеристики существования. Экзистенциальный взгляд — это то, как вы видите само существование. Изменение всего лишь одной части экзистенциального взгляда приведет к изменению вашего взгляда на саму Вселенную.
Этот пост не посвящен перечислению всех парадигм языков программирования и их сходствам и различиям. Скорее, этот пост посвящен рассмотрению нескольких парадигм, изучению того, как эти парадигмы иллюстрируют экзистенциальные взгляды самого языка, и изучению того, как эти парадигмы влияют на наше мышление. Некоторые программисты предпочитают определенные языки не по техническим причинам, а по причинам, связанным с языковой парадигмой. Язык как раз им «подходит». Парадигмы в языках программирования также влияют на наше мышление и наши экзистенциальные взгляды. Изучая более одной парадигмы, мы становимся способными видеть вещи по-разному.
Эти нюансы и отличия не всех интересуют, но меня они интересуют, и я надеюсь, что вам они тоже будут интересны.
Мы будем использовать код в качестве примеров!
Парадигма типов данных
Типы данных — одна из ключевых фундаментальных частей, составляющих парадигму языка. Они классифицируют данные и отличают их от других форм данных. Давайте сравним типы данных в Perl и Python, например.
Python имеет 4 примитивных типа данных:
- Строки («привет», «а», «5»)
- Целые числа (100, 42, 5)
- Поплавки ( 10.14, 3.14, 5.0 )
- Булевы значения (Истина, Ложь)
Чтобы проиллюстрировать эту парадигму на языке программирования Python, «5», 5.0 и 5 — это разные типы данных. «5» — это строка, 5.0 — это число с плавающей запятой, а 5 — это целое число. Вы можете доказать это, используя встроенную функцию type() в интерпретаторе Python, таком как iPython (или обычный интерпретатор будет работать).
(Обратите внимание, что In[x]: и Out[x]: взяты из интерпретатора iPython и не являются кодом, весь код идет после)
In [1]: type(5) Out[1]: int In [2]: type("5") Out[2]: str In [3]: type(5.0) Out[3]: float
Сравните это с таким языком программирования, как Perl, и мы увидим другую парадигму типов данных. Perl имеет 3 примитивных типа данных:
- Скаляры («строки», 5 и ссылки ($scalarref = \$foo;))
- Массивы ( @array = (1, 2); )
- Хеши ( %hash = ( «1» =› «Дэви Джонс»); )
В Perl многие вещи могут быть «скалярами». Строка типа «5» является скаляром, 5.0 — скаляром, 5 — скаляром. Парадигма Perl не различает эти фрагменты данных так, как это делает Python. В глазах Perl это один и тот же тип данных.
В этом нет ничего «неправильного», но он показывает совершенно иной способ мышления, чем такой язык, как Python. Python гораздо более педантично относится к типу данных, чем Perl. Чтобы доказать это, давайте воспользуемся встроенной в Perl функцией ref() для некоторых переменных, чтобы проиллюстрировать, как Perl рассматривает типы данных.
Я использую интерпретатор Perl, встроенный в GNU/Linux. Вы можете получить доступ к этому интерпретатору, введя это в терминал:
perl -de 0
Давай начнем. (Обратите внимание, что DB‹1› взят из ввода в терминале и не является фактическим кодом, весь код находится после DB‹x›)
DB<1> use strict; use warnings; DB<2> $string = "a series of chars"; DB<3> $int = 10; DB<4> %hash = ( "1" => "Davy Jones" ); # When using the ref() function in Perl, we have to # reference the variable with a \. # So, \$scalar is a reference to $scalar DB<5> print( ref( \$string ) ); # output SCALAR DB<6> print( ref( \$int ) ); # output SCALAR # (notice that Perl sees an int and a string as the same) DB<12> print( ref( \%hash ) ); # output HASH # (Perl does distinguish hashes from scalars)
Это не означает, что парадигма Python или Perl лучше. Вы можете написать программу, которая выполняет одну и ту же задачу на любом языке программирования. Скорее, он представлен для того, чтобы показать, как небольшая деталь может представлять собой масштабное изменение экзистенциальных взглядов по сравнению с парадигмами.
Вы также можете сравнить парадигмы других языков программирования, но на этой иллюстрации мы сосредоточимся только на Perl и Python.
Парадигма итерации
Еще одно место, где мы видим различия в парадигме, — это итерация. На этой иллюстрации мы сравним итерацию с тремя языками программирования: Python, Perl и C.
Я думаю, что итерация — это одна из областей, где Perl действительно хорош, и, надеюсь, после этой иллюстрации вы поймете, почему! Вот код, который мы введем в интерпретатор Perl. Мы определим три массива, а затем пройдемся по каждому из них.
DB<1> @a1 = (1,2,3); DB<2> @a2 = (4,5,6); DB<3> @a3 = (7,8,9); DB<4> for $_(@a1, @a2, @a3) { print($_) }; # 123456789
Эквивалентом массива в Perl является список в Python. Теперь у Python есть способы перебирать несколько списков, как это делает Perl с такими вещами, как *args, но это не было бы «эквивалентом» в парадигме Python. У Python совершенно другая парадигма, давайте напишем код для иллюстрации.
In [1]: a1 = [1,2,3] In [2]: a2 = [4,5,6] In [3]: a3 = [7,8,9] In [4]: for each in [ a1, a2, a3 ]: ...: print(each) ...: # output is... [1, 2, 3] [4, 5, 6] [7, 8, 9]
Как видите, Python распечатал 3 списка, а не переменные в каждом списке одну за другой. Мы получили бы тот же результат, если бы заменили квадратные скобки на круглые скобки или полностью их удалили. Наблюдать.
In [5]: for each in a1, a2, a3 : ...: print(each) ...: [1, 2, 3] [4, 5, 6] [7, 8, 9] In [6]: for each in (a1, a2, a3) : ...: print(each) ...: [1, 2, 3] [4, 5, 6] [7, 8, 9]
Опять же, мы МОГЛИ бы создать функцию на Python, используя *args для перебора каждого списка и получения того же результата, что и Perl, но это не эквивалентный код для представления парадигмы. Вот почему. Я думаю, что Perl сияет в итерациях со своей парадигмой, потому что, чтобы получить эквивалент в коде парадигмы, нам нужно было бы сделать это….
In [9]: for each in a1: print(each); ...: for each in a2: print(each); ...: for each in a3: print(each); 1 2 3 4 5 6 7 8 9
Как видите, это очень утомительно, а с парадигмой Python вам придется перебирать каждый список по отдельности, а не включать их в один оператор. Вы обнаружите это, если напишете функцию с *args.
In [12]: def iterate(*args): ...: for each in args: ...: for e in each: ...: print(e) ...: ...: In [13]: iterate(a1, a2, a3) 1 2 3 4 5 6 7 8 9
Таким образом, хотя и в Perl, и в Python есть циклы for для итерации, их парадигма с этими циклами for совершенно различна. Но эти два примера не отражают всех различных парадигм в отношении итерации. Например, в C совершенно другая парадигма. Давайте проиллюстрируем это на некотором коде.
#include <stdio.h> // Anything after // is a comment // Let's print numbers from 1 to 10 int main() { int iteration; for (iteration = 1; iteration < 11; ++iteration) { printf("%d ", iteration); } return 0; } // output is: // 1 2 3 4 5 6 7 8 9 10
В таком языке, как C, нет парадигмы «для каждого в итерации». C имеет совершенно другую парадигму, где вы должны инициализировать начальное значение, иметь условие while, а затем операцию.
Надеюсь, с этими примерами вы теперь лучше знакомы с тем, о чем я говорю, когда говорю о парадигмах языков программирования и о том, как язык мыслит по-другому.
Парадигма назначения
Языки программирования также имеют разные экзистенциальные взгляды на присваивание. В присваиваниях есть явные и неявные присваивания. Python является неявным, что означает, что вы присваиваете данные имени переменной, а Python выясняет, что это такое. Чтобы определить целое число в Python, вы можете просто сказать:
integer = 6
И бум, вы закончили с этим. Вам не нужно объявлять, к какому типу данных относятся данные, потому что Python уже знает это из-за своей неявной парадигмы. В других языках с явной парадигмой присваивания вы не можете этого сделать. Вы должны сначала объявить, к какому типу данных относится переменная, а затем присвоить ей значение соответствующего типа данных. Так, например, следующий код на C выдаст ошибку.
#include <stdio.h> int main() { // notice no declaration of data type // this code will give an error i = 5; printf("%d", i); return 0; }
Если вы попытаетесь работать с этим кодом, вы получите что-то вроде следующего:
gcc /tmp/ezyISLlADo.c -lm /tmp/ezyISLlADo.c: In function 'main': /tmp/ezyISLlADo.c:6:1: error: 'i' undeclared (first use in this function) 6 | i = 5; | ^ /tmp/ezyISLlADo.c:6:1: note: each undeclared identifier is reported only once for each function it appears in
Если вы объявите тип данных, а затем попытаетесь его скомпилировать, все будет в порядке.
#include <stdio.h> int main() { // notice the declaration of int int i = 5; printf("%d", i); return 0; }
Различия в парадигме присвоения переменных идут еще дальше. Например, в некоторых языках есть парадигма присвоения переменной константы. Этой концепции нет в таких языках, как Python. Все переменные в Python по умолчанию изменяемы, то есть их можно изменить. В таком языке, как Rust, переменные неизменяемы по умолчанию и, следовательно, являются константами. Вы должны объявить переменные изменяемыми в таком языке, как Rust.
fn main() { // notice the mut keyword // this declares a variable to be mutable let mut x = 5; println!("The value of x is: {x}"); x = 6; println!("The value of x is: {x}"); }
Но даже тогда это не покрывает всех различий в парадигмах языков программирования с присваиванием. Мы не будем охватывать их все, но давайте рассмотрим еще два отличия.
В таком языке, как Java, есть понятие «общедоступных», «приватных» и «защищенных» переменных. Эти метки управляют доступом к переменным. Этой концепции не существует в таком языке, как Python.
Еще одно отличие — несколько заданий. В Python и других языках вы можете сделать что-то вроде этого:
x = y = 5
На таком языке, как Rust, вы не сможете этого сделать, вы получите ошибку, и опять же это связано с парадигмой языка программирования.
Заключение
Итак, это краткий обзор парадигм языка программирования при рассмотрении типов данных, итераций и назначений. Надеюсь, вы поймете, насколько это широкая тема, и найдете ее интересной. Мы коснулись только трех областей, в этих областях есть еще что исследовать, даже есть другие области, которые мы не рассмотрели!
Я думаю, интересно подумать о том, как языковые парадигмы влияют на наше мышление. Некоторые люди предпочитают определенные языки другим, и я не думаю, что это просто синтаксис, я думаю, что некоторые языки лучше соответствуют встроенной парадигме программистов в их сознании, чем другие. Я изучаю это уже несколько лет, и я очарован этим.
Если вам понравилось это, вы хотели бы получить больше информации об этом или у вас есть какие-либо предложения / исправления, пожалуйста, сообщите об этом в разделе комментариев ниже!