Обновить
14.28

Функциональное программирование *

От Lisp до Haskell

Сначала показывать
Порог рейтинга
Уровень сложности

Не-фон неймановский компьютер на базе комбинаторной логики

Время на прочтение8 мин
Охват и читатели27K
Здравствуйте. В этой статье я расскажу про свой хобби-проект не-фон неймановского компьютера. Архитектура соответствует функциональной парадигме: программа есть дерево применений элементарных функций друг к другу. Железо — однородная статическая сеть примитивных узлов, на которую динамическое дерево программы спроецировано, и по которой программа «ползает» вычисляясь.


Примерно так работает дерево, только здесь для наглядности вычисляются арифметическое выражение, а не комбинаторное; шаг на рисунке — один такт машины.

Сейчас готов ранний прототип, существующий как в виде потактового программного симулятора, так и в виде реализации на ПЛИС.
Читать дальше →

Немного о каррировании в Haskell

Время на прочтение2 мин
Охват и читатели16K
Читая М. Липовача «Изучай Haskell во имя добра!», я поначалу не понимал, чем частичное применение отличается от каррирования. Потратил некоторое время на разбор данного вопроса и набросал себе «шпаргалку» по обозначенной теме.
Читать дальше →

Категории Клейсли

Время на прочтение9 мин
Охват и читатели28K

Композиция логирования


Вы видели, как сделать категорию типов и чистых функций. Я также упомянул, что есть способ смоделировать побочные эффекты, или нечистые функции, в рамках теории категорий. Давайте рассмотрим пример: функции, которые логируют или записывают ход своего выполнения.
Читать дальше →

Письмо Дейкстры: почему обучение программированию нужно начинать с функционального языка

Время на прочтение4 мин
Охват и читатели103K


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

Мы в Хекслете недавно запустили новую версию, ключевой особенностью которой стали практические упражнения по программированию в браузере. В связи с этим мы стали получать еще больше писем от начинающих программистов с вопросами вроде «с чего начать». С одной стороны, они хотят выложить бета-версию приложения в app store через неделю. С другой стороны, мы понимаем, что за такой короткий срок, наверное, можно научиться кодить приложения, но нельзя научиться программировать. И сложно решить, что лучше: как можно быстрее научить созданию простых приложений без реального понимания программирования, алгоритмов и их вычислительной сложности, а потом начать знакомство с этими важными темами, или начать «с начала», и органично придти к созданию приложений и продуктов после освоения фундамента.

В 2001 году, Эдсгер Дейкстра написал письмо экономическому совету университета Техаса. В нем знаменитый ученый призывает членов совета задуматься о смене языка программирования для вводного курса. К сожалению, язык был заменен на Java. Примерно в то же время MIT сменили язык курса «Структура и интерпретация компьютерных программ» с функционального Scheme (диалекта LISP) на Python.

Сегодня мы публикуем перевод этого письма.

Членам Экономического Совета


Я пишу вам по поводу слуха о замене языка во вводном курсе по программированию с функционального языка Haskell на императивный язык Java. Я считаю, что Совет должен взять на себя ответственность, чтобы решение не было принято на неправильном уровне.
Читать дальше →

Об именах в Haskell

Время на прочтение5 мин
Охват и читатели7.2K
Имя любого идентификатора в Haskell начинается с буквы, за которой следует
ноль или более букв, цифр, символов подчёркивания _ и одинарной кавычки '. В качестве буквы рассматриваются только латинские символы в интервалах a..z и A..Z. Символ _ принято считать буквой, в следствии чего имя функции может начинаться с этого символа, но не может состоять только из него, в виду того, что в образцах Haskell он обозначает любое значение. Имена функций, составленные не из символов набора ascSymbol, обязательно должны начинаться со строчной буквы или символа _. Имена пространств имён, типов данных, конструкторов данных и классов типов составленные не из символов набора ascSymbol должны начинаться с прописной буквы. В данной заметке даётся некоторая информация об использовании символов набора ascSymbol в идентификаторах Haskell.
Читать дальше →

Вычисление факториала на числах Чёрча

Время на прочтение5 мин
Охват и читатели26K
Доброго дня, друзья!

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

Для того, чтоб жизнь мёдом не казалась, ограничим себя небольшим подмножеством языка JavaScript, а именно, будем использовать только анонимные функции от одного аргумента. Больше нам ничего не потребуется (ну почти).

Начнем с определения факториала, и посмотрим, что нам понадобится в процессе решения задачи:

var fact = function (n) {
  if (n === 0) return 1;
  return n * fact(n - 1);
};


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

Готовы?
Ну тогда поехали.

Категории, большие и малые

Время на прочтение8 мин
Охват и читатели37K
Это четвертая статья в цикле «Теория категорий для программистов».

Понять пользу категорий можно изучая различные примеры. Категории бывают всех форм и размеров и часто появляются в самых неожиданных местах. Мы начнем с самых простых.

Без объектов


Самая простая категория — без объектов и, как следствие, без морфизмов.
Читать дальше

Clojure — трансдьюсеры, редьюсеры и прочая муть

Время на прочтение14 мин
Охват и читатели24K
В последнее время определенную известность получили transducers — новая фишка из еще не вышедшей Clojure 1.7. На момент написания статьи актуальна Сlojure 1.7-alpha5, но уже успело появиться изрядное количество портов трансдьюсеров на разнообразные языки: Python, Ruby, JavaScript, PHP, Java, C++, Lua, Erlang. И… это немного обескураживает. Ведь довольно давно (еще в Clojure 1.5) добавили библиотеку reducers.Так вот про редьюсеры никто особо не говорил,никуда ничего не портировал, хотя, вроде как, делают они схожие вещи… Или нет?

Давайте разберемся, для чего нам в Clojure понадобились все эти reducers & transducers (они нам правда нужны?), как они работают, как их использовать… И выясним наконец, не пора ли выкидывать reducers на свалку.
Сворачиваемся...

Языки программирования. Композиционный взгляд

Время на прочтение5 мин
Охват и читатели9.6K
Здравствуй, Хабр! Сегодня хотел бы поднять вопрос об использовании композиций и их роли в программировании. Те, кто сталкивался с функциональными языками, скорее всего слышали о них, а те, кто не сталкивался, возможно, узнают что-нибудь новое. Надеюсь на интересную дискуссию в конце статьи об их применении. Эшер для привлечения внимания.


Поехали

Типы и функции

Время на прочтение13 мин
Охват и читатели61K
Это третья статья в цикле «Теория категорий для программистов».

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

Кому нужны типы?


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

image


Читать дальше →

Когда использовать ООП, а когда — ФП?

Время на прочтение3 мин
Охват и читатели34K
Грубо говоря, у ФП и ООП схожие возможности в выражении сложных конструкций и инкапсуляции программ на мелкие куски, которые можно комбинировать между собой.

Самая большая разница между двумя этими «философиями» состоит в том, как данные соотносятся с операциями над данными.

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

При ООП подходе программист составляет новые объекты и расширяет существующие путём добавления к ним методов.

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

При ФП подходе программист пишет новые функции.
Читать дальше →

Функциональное программирование в Swift. Начало

Время на прочтение15 мин
Охват и читатели26K


Предисловие переводчика.


Отмечая окончание 2014 года, известная Swift группа SLUG из Сан-Франциско выбрала 5 наиболее популярных Swift видео за 2014 с организованных ею встреч. И среди них оказалось выступление Chris Eidhof «Функциональное программирование в Swift».
Сейчас Chris Eidhof — известная личность в Swift сообществе, он — автор недавно вышедшей книги «Functional programming in Swift», один из создателей журнала objc.io, организатор конференции «Functional Swift Conference», прошедшей 6-го декабря в Бруклине и будущей конференции UIKonf.
Но я открыла его, когда он, один из первых, опубликовал очень простую элегантную статью об эффективности функционального подхода в Swift к JSON парсингу.
В этой статье нет недоступных для понимания концепций, никаких мистических математических «химер» типа «Монада, Функтор, Аппликативный функтор», на которых Haskell программисты клянутся перед оставшимся миром, закатывая глаза.
Там нет и таких нововведений Swift, как дженерики (generics) и «вывод типа» (type inference).
Если вы хотите плавно «въехать» в функциональное программирование в Swift, то вы должны познакомиться с его статьей «Parsing JSON in Swift» и выступлением на SLUG «Functional Programming in Swift».
Читать дальше →

Категория: суть композиции

Время на прочтение7 мин
Охват и читатели64K
Это вторая статья в цикле «Теория категорий для программистов».

Категория — очень простая концепция.

Категория состоит из объектов и стрелок, которые направлены между ними. Поэтому, категории так легко представить графически. Объект можно нарисовать в виде круга или точки, а стрелки — просто стрелки между ними. (Просто для разнообразия, я буду время от времени рисовать объекты, как поросят а стрелки, как фейерверки.) Но суть категории — композиция. Или, если вам больше нравится, суть композиции — категория. Стрелки компонуются так, что если у вас есть стрелка от объекта А к объекту B, и еще одна стрелка из объекта B в C, то должна быть стрелка, — их композиция, — от А до С.

image
Читать дальше →

Ближайшие события

Теория категорий для программистов: предисловие

Время на прочтение5 мин
Охват и читатели112K
Вот уже некоторое время я обдумываю идею написать книгу о теории категорий для программистов. Не компьютерных теоретиков, программистов — скорее инженеров, чем ученых. Я знаю, что это звучит безумно, и я сам достаточно напуган. Я знаю, что есть огромная разница между наукой и техникой, потому, что я работал по обе стороны баррикад. Но у меня всегда был очень сильный порыв объяснить вещи. Я восхищаюсь Ричардрм Фейнманом, который был мастером простых объяснений. Я знаю, я не Фейнман, но я буду стараться изо всех сил. Я начинаю с публикации этого предисловия, которое должно мотивировать читателя изучить теорию категорий, и надеюсь на начало дискуссии и обратную связь.

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

Эффективный JSON с функциональными концепциями и generics в Swift

Время на прочтение14 мин
Охват и читатели12K
Это перевод статьи Tony DiPasquale «Efficient JSON in Swift with Functional Concepts».

Предисловие переводчика


Передо мной была поставлена задача: закачать данные в формате JSON с Flickr.com о 100 топ местах, в которых сделаны фотографии на данный момент, в массив моделей:
Читать дальше →

Функциональное программирование на CoffeeScript с библиотекой f_context

Время на прочтение5 мин
Охват и читатели4.6K
Тем, кто сталкивался с функциональными языками программирования наверняка знакома такая конструкция:
  fact(0) -> 1
  fact(N) -> N * fact(N - 1)

Это один из классических примеров ФП — вычисление факториала.
Теперь это можно делать и на CoffeeScript с библиотекой f_context, просто оборачивая код в f_context ->, например:
  f_context ->
    fact(0) -> 1
    fact(N) -> N * fact(N - 1)

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

F# адвент календарь по английски на 2014

Время на прочтение1 мин
Охват и читатели3.7K
У наших друзей из Японии есть замечательное событие, называемое F#-ский адвентский календарь. Каждый день, начиная с первого декабря по 31 декабря, один класный чел-доброволец пишет новую статью о F#. Это же просто замечательный подход для празднования Рождества, не правда ли?

Давайте же поддержим эту инициативу и сделаем английскую версию такого календаря. Две блог статьи в день лучше одного, неправда ли? Нам нужен 31 доброволец, готовый подготовить и опубликовать статью о F# в назначенный день.
Подробности

Обработка ошибок в Swift — меч и магия

Время на прочтение5 мин
Охват и читатели17K
Если издали видно общую картину, то вблизи можно понять суть. Концепции, которые казались мне далекими и, прямо скажем, странными во время экспериментов с Haskell и Scala, при программировании на Swift становятся ослепительно очевидными решениями для широкого спектра проблем.

Взять вот обработку ошибок. Конкретный пример – деление двух чисел, которое должно вызвать исключение если делитель равен нулю. В Objective C я бы решил проблему так:

NSError *err = nil;
CGFloat result = [NMArithmetic divide:2.5 by:3.0 error:&err];
if (err) {
    NSLog(@"%@", err)
} else {
    [NMArithmetic doSomethingWithResult:result]
}

Со временем это стало казаться самым привычным способом написания кода. Я не замечаю, какие загогулины приходится писать и как косвенно они связаны с тем, что я на самом деле хочу от программы:

Верни мне значение. Если не получится – то дай знать, чтобы ошибку можно было обработать.

Я передаю параметры, разыменовываю указатели, возвращаю значение в любом случае и в некоторых случаях потом игнорирую. Это неорганизованный код по следующим причинам:

  • Я говорю на машинном языке – указатели, разыменование.
  • Я должен сам предоставить методу способ, которым он уведомит меня об ошибке.
  • Метод возвращает некий результат даже в случае ошибки.

Каждый из этих пунктов – источник возможных багов, и все эти проблемы Swift решает по-своему. Первый пункт, например, в Swift вообще не существует, поскольку он прячет под капотом всю работу с указателями. Остальные два пункта решаются с помощью перечислений.
Читать дальше →

Пальчиковые деревья (часть 2. Операции)

Время на прочтение13 мин
Охват и читатели6.6K
Статья будет состоять из 3х частей:
Пальчиковые деревья (часть 1. Представление)
Пальчиковые деревья (часть 2. Операции)
Пальчиковые деревья (часть 3. Применение)

Пальчиковые Деревья как Последовательности



В первой части статьи мы рассмотрели пальчиковые деревья как перспективную структуру в качестве немутабельных последовательностей. И научились создавать пальчиковые деревья. Хочу заметить, научились создавать так, что стало принципиально невозможно построить неправильные деревья. Теперь наша задача научится работать с пальчиковыми деревьями как с последовательностями: научится присоединять к началу и концу последовательности, научится легко отделять от обоих концов последовательности, а также соединять несколько деревьев в одно.
Читать дальше →

Pipe matching в ЯП Clojure (метапрограммирование в Lisp для начинающих)

Время на прочтение9 мин
Охват и читатели13K


Введение


Несколько дней назад я открыл для себя замечательный ЯП Clojure — один из современных диалектов Lisp, особенностью которого является хорошая реализация средств многопоточности, компиляция в байткод jvm, соответственно возможность использования java — библиотек, jit-компиляция и т.д. Про Clojure можно почитать например тут. Но в этой статье речь пойдёт о метапрограммировании. Lisp устроен таким образом, что данные и код в нём — одно и то же. Объявления функций, макросов, вызовы функций, развёртывание макросов — в Lisp это всё просто списки, возможно вложенные друг в друга.

(defn square [foo] (* foo foo))
(defmacro show-it [foo] `(println ~foo))


Такое единство кода и данных предоставляет мощные возможности для метапрограммирования — код который пишет код, который пишет код, который пишет код и т.д. — это самое обычное дело для программирования на Lisp. В compile-time нам полностью доступен весь функционал языка, мы можем вызывать функции, развёртывать макросы, возможно рекурсивно. Например, если мы определим вот такой макрос:
Читать дальше →