GithubHelp home page GithubHelp logo

scalacourse's Introduction

Syllabus

Week 1

Week 1

Курс посвящен функциональному программирования на языке Scala. Основная цель не изучение конкретного языка, но усвоение базовых принципов функционального программирования.

1.1. Парадигмы программирования

Парадигма - в науке описывает различные концепции или образ мышления в некоторой научной дисциплине

В программировании можно выделить три основные парадигмы:

  • императивная
  • функциональная
  • логическая

Объектно-ориентированное программирование часто относят к отдельному виду программирования, но на мой взгляд это ООП - нечто ортгональное трем этим парадигмам в том смысле, что оно может хорошо сочетаться как с императивным программированием, так и с функциональным и даже логическим программированием.

Императивное программирование это

  • изменяемые переменные
  • использование операции присвания
  • средства для изменения потока выполнения (if-then-else, loops, continue, return)

Наиболее распространенный неформальный способ понимать имеративные программы, как последовательности инструкций для компьютера фон Неймана.

Фон Нейман был одним из пионеров, создав первый компьютер около 1945 года. Компьютер фон Неймана состоит в основном из процессора и памяти, и шины, которая читает инструкции и данные из памяти в процессор. И что важно, что ширина этой шины составляет одно машинное слово, что в настоящее время составляет 32 или 64 бита.

Теперь оказывается, что эта модель компьютера в немалой степени сформировала программирование

  • изменяемые переменные соответствуют ячейкам памяти компьютера фон Неймана
  • разыменование переменной соответствует инструкциям чтения данных в компьютер
  • присваивание переменной соответствует инструкции записи
  • управляющие структуры транслируются в последовательность циклов.

Проблема кроется в том, что при масштабировании мы хотим избежать осмысления программ слово в слово. Мы хотим рассыждать в более крупных структурах. Это было аргументом Джона Бэкуса, в своей лекции премии Тьюринга, под названием "Может ли программирование освободиться от стиля фон Неймана".

Примечательно, что Джон Бэкус был на самом деле изобретателем первого языка высокого уровня. Это был Фортран в 1950 году, так что более чем через двадцать лет спустя он обнаружил, что традиционное направление императивного программирования затухает и что требуется что-то новое. И новая вещь, которую он предлагает это функциональное программирование. Так Джон Бэкус утверждал, что в итоге чистое императивное программирование ограничено узким местом архитектуры фон Неймана, что означает, что означает, что мы постепенно осмысляем структуры данных.

Если мы хотим иметь возможность масштабирования, то мы должны определять абстракции более высокого уровня, такие как коллекции, полиномы, геометрические фигуры, строки, документы и так далее. И чтобы быть основательным, нам нужно иметь теории с этими абстракциями высокого уровня, коллекциями, фигурами и так далее, о чём мы можем рассуждать.

И чтобы быть основательным, нам нужно иметь теории для работы с этими абстракциями высокого уровня, коллекциями, фигурами и так далее, о чём мы можем рассуждать.

Так что же такое теория? В математике теории состоит из

  • одного или нескольких типов данных
  • операций над этими типами
  • законов, которые описывают отношения между значениями и операциями

При этом важно, что математическая теория не описывает изменяемости. Изменяемость означает, что я изменил что-то, сохраняя идентичность вещи.

Например, теория полиномов описывает операцию сложения двух полинов

(a*x + b) + (c*x + d) = (a +c)*x + (b + d)

Но есть одна вещь, которую теория полиномов не делает - она не описывает оператор для изменения коэффициента, сохраняя многочлен неизменным.

Тогда как в императивном\ООП стиле программирования можно определить полином следующим образом:

class Polynomial { double[] coefficient; }
Polynomial p = ...;
p.coefficient = 42;

определив операцию изменения коэффициентов. В математике это недоступно.

Таким образом, если мы хотим следовать в наших высокоуровневых конструкциях и концепциях, в них нет места изменяемости.

Это приводит к новому стилю программирования, в котором мы хотим

  • сконцентрироваться на определении теории для операторов, выраженных в виде функций
  • избежать изменяемости
  • иметь мощные средства для абстракции и конструирования функций

Есть несколько способов ввести определение фукционального программирования

  • в ограничинном смысле ФП значит программировать без использования изменяемых переменных, присваиваний, циклов и прочих конструкций императивного программирования для изменения потока выполнения программы
  • в более широком понимании ФП означает концентрацию на функциях

В частности функции могут быть тем, что производится, потребляется и что является составной частью других функций.

Все это можно реализовать на любом языке программирования. Но ФП упрощает это.

Соответсвенно, есть несколько способов ввести определение функционального языка программирования

  • в ограниченно смысле язык ФП не имеет изменяемых переменных, присваиваний, структур для изменения потока выполнения программы (примеры: Pure Lisp, XSLT, XPath, XQuery, Haskell)
  • в более широком смысле язык ФП включает и облегчает создание элегантных программ, сфокусированных на фукциях (примеры: Lisp, Scheme, Racket, Clojure, SML, Ocaml, F#, Scala, Smalltalk, Ruby(!))

В частности, функции в языкае ФП являются функциями высшего порядка

Функция высшего порядка - функция, принимающая в качестве аргумента другие функции и возвращаюшая другую функцию в качестве результата

Мое небольшое дополнение

из книги Р.Мартина "Чистая архитектура":

  1. Структурное программирование накладывает ограничение на прямую передачу управления

Первой, получившей всеобщее признание (но не первой из придуманных), была парадигма структурного программирования, предложенная Эдсгером Вибе Дейкстрой в 1968 году. Дейкстра показал, что безудержное использование переходов (инструкций goto) вредно для структуры программы. Как будет описано в последующих главах, он предложил заменить переходы более понятными конструкциями if/then/else и do/while/until.

  1. Объектно-ориентированное программирование накладывает ограничение на косвенную передачу управление

Второй парадигмой, получившей широкое распространение, стала парадигма, в действительности появившаяся двумя годами ранее, в 1966-м, и предложенная Оле-Йоханом Далем и Кристеном Нюгором. Эти два программиста заметили, что в языке ALGOL есть возможность переместить кадр стека вызова функции в динамическую память (кучу), благодаря чему локальные переменные, объявленные внутри функции, могут сохраняться после выхода из нее. В результате функция превращалась в конструктор класса, локальные переменные — в переменные экземпляра, а вложенные функции — в методы. Это привело к открытию полиморфизма через строгое использование указателей на функции.

  1. Функцианальное программирование накладывает ограничение на присваивание

Третьей парадигмой, начавшей распространяться относительно недавно, является самая первая из придуманных. Фактически изобретение этой парадигмы предшествовало появлению самой идеи программирования. Парадигма функционального программирования является прямым результатом работы Алонзо Чёрча, который в 1936 году изобрел лямбда-исчисление (или λ-исчисление), исследуя ту же математическую задачу, которая примерно в то же время занимала Алана Тьюринга. Его λ-исчисление легло в основу языка LISP, изобретенного в 1958 году Джоном Маккарти . Основополагающим понятием λ-исчисления является неизменяемость — то есть невозможность изменения значений символов. Фактически это означает, что функциональный язык не имеет инструкции присваивания. В действительности большинство функциональных языков обладает некоторыми средствами, позволяющими изменять значение переменной, но в очень ограниченных случаях.

Можно заметить, что каждая парадигма что-то отнимает у нас. Три парадигмы вместе отнимают у нас инструкции goto, указатели на функции и оператор присваивания.

Есть ли у нас еще что-то, что можно отнять? Вероятно, нет. Скорее всего, эти три парадигмы останутся единственными, которые мы увидим, — по крайней мере единственными, что-то отнимающими у нас.

Доказательством отсутствия новых парадигм может служить тот факт, что все три известные парадигмы были открыты в течение десяти лет, между 1958 и 1968 годами. За многие последующие десятилетия не появилось ни одной новой парадигмы.

1.2. Элементы программирования

Каждый ЯП предоставляет:

  • примитивные выражения, которые представляют простейшие элементы языка
  • способы для комбинирования выражений
  • способы абстракции выражений (абстракция здесь означает, что мы даем выражению имя и далее ссылаемся на выражение по имени)

Evaluation

  1. взять самый левый оператор
  2. вычислить левый и правый операнды
  3. применить операцию к операнду
  4. процесс вычисления завершается, когда получено итоговое значений всего выражения

Пример операции

(2 * pi) * radius
-> (2 * 3.14159) * radius
-> 6.28318 * radius
-> 6.28318 * 10
-> 62.8318

Задавая функцию, можно задать параметры и их тип, а также тип возвращаемого значения

def square(x: Double): Double = x * x

Значение, возвращаемое функцией вычисляется по тем же принципам, что и вычисление результата операции

  1. вычислить значение всех аргументов слева направо
  2. заменить применение функции на правую часть объявления функции
  3. заменить параметры функции на вычисленные значения аргументов
def sumOfSquares(x: Double, y: Double): Double = square(x) + square(y)

sumOfSquares(3, 2 + 2)
-> sumOfSquares(3, 4)
-> square(3) + square(4)
-> 9 + square(4)
-> 9 + 16
-> 25

Данная схема вычисления называется модель подстановок (substitution model). Идея здесь в том, что вычисление сводит (редуцирует) выражение к значению. И этот процесс редукции может быть выражен как последовательность простых шагов перезаписи, которые перезаписывают терм выражения до тех пор, пока он не превратится в значение. Данная модель может применена к любому выражению, каким длинным оно не было, пока оно не имеет побочных эффектов (side effects).

Фактически было показано, что эта модель может выразить любой алгоритм, так что она эквивалентна машине Тьюринга. И это было показано задолго до появления функционального программирования, и, фактически, даже самих компьютеров, специалистом по логике Алонзо Чёрчем в теории лямбда-исчислений.

Notes

бага с ошибкой запуска console в sbt https://www.coursera.org/learn/progfun1/programming/xIz9O/example-assignment/discussions/threads/ZJ0KiNPYEeiq8BLsBpYkZA

scalacourse's People

Contributors

ml21 avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.