Дочитал давеча «семь языков за семь недель«. Языков программирования, разумеется. Ruby, IO, Prolog, Scala, Erlang, Clojure и Haskell. Прекрасное чтиво. Ни один из них в резюме я, конечно, не добавлю, но прогнать через себя за раз столько языков с разными парадигмами — как в стронциевый душ зайти: бодрит, и голова светится.
Книга строится по достаточно простой схеме: базовое описание языка + 3 дня теории и заданий. Несмотря на название, недели на один язык много. На два — в самый раз. Задания немного неоднородные. Иногда за пол часа можно целый день сделать. Иногда один день растягивается на два вечера. Вот так, например, выглядят задания для второго дня Scala:
Найти:
- Обсуждение, как работать с файлами в Scala
- Чем отличается closure от code block
Сделать:
- Используя foldLeft посчитать суммарный размер всех строк в коллекции
- Написать Censor трэйт (эдакий гибрит между интерфейсом и классом), который будет заменять матерные слова в тексте на более культурные эквиваленты. Словарь мата хранить в map
- Загрузить словарь с матом из файла
По языкам, какие-то больше понравились, какие-то меньше. В основном больше.
Ruby
Ruby приятен и красив. Нормальный такой интерпретируемый объектно-ориентированный язык. Изначально создавался как язык, на котором приятно писать. Я его немного и так знал, поэтому напрягаться не пришлось. Для метапрограммирования Руби — это маленький рай. Можно добавлять методы на лету, включать в класс модули или просто добавлять обработчики на вызов несуществующих методов. Приятно.
1 2 3 4 5 6 7 8 9 |
class Extendable def method_missing name, *args puts "В рот мне ноги, нет такого метода! #{name}" end end ex = Extendable.new ex.callSomethingUnknown #=> В рот мне ноги, нет такого метода! callSomethingUnknown |
IO
IO вообще великолепен. Как JavaScript — прототипный. Как Objective C — объекты общаются между собой отправкой сообщений. Смесь немного ядерная, но что-то щелкает в мозгу. Создавать новые объекты через Object clone , а не new Object() для прототипного языка, по-моему, гениальное решение. Есть аналог method_missing от руби — forward. Пример кода скопировал из своего прошлого поста, просто чтобы был тут.
1 2 3 4 5 6 7 8 9 10 |
person := Object clone person name := "John" person forward := method( writeln("Did you just call me ", call message name, "?") ) writeln(person name) //==> John person jerk //==> Did you just call me jerk? |
Prolog
Prolog — это просто нечно. Попадались мне языки процедурные, объектные, гибридные и функциональные, но чтобы логический — как-то чаша проходила мимо. Если в «нормальных» языках мы описываем, как мы хотим получить результат, то в Прологе — мы записываем словарь фактов, а затем задаём вопросы. Это просто шикарно. Например, можно сделать такой словарь: пепси — это шипучка, водка — это спиртяга. Шипучки сладкие, в спиртяга — на вкус как гумно. Чтобы узнать, какой на вкус напиток, нужно посмотреть, какой на вкус его тип.
В синтаксисе пролога, факты будут выглядеть так:
1 2 3 4 5 6 7 8 9 10 |
% типы напитков drink_kind(pepsi, soda). drink_kind(vodka, spirit). % вкус каждого типа taste(soda, sweet). taste(spirit, shit). %как определить вкус напитка drink_taste(Drink, Taste):- drink_kind(Drink, X), taste(X, Taste). |
И если потом прологу задать вопрос: «дружище, а водка на вкус, это как?», то ответ будет прямолинеен как китайский бумеранг:
1 2 3 |
?- drink_taste(vodka, X). X = shit |
Мао не смог бы сказать лучше.
У меня в голове сейчас куча идей, как можно было бы пролог припахать в реальному проекту. Например, одна такая: нужно сэмулировать вождение водителя BMW на карте. Чисто для тестирования. И вместо того, чтобы плодить стандартное полотнище кода, можно скормить прологу особенности поведения водителей BMW, как они перекрестки проезжают, трогаются с места, перестраиваются, и потом спросить у пролога — «товарищ, в вот на этой улице, как бы он проехал?».
Пролог, единственный из всех языков, который я прямо сейчас буду учить дальше.
Scala
Scala — объектно-ориентированный/функциональный язык, который работает в Java Virtual Machine (JVM), поэтому автоматом получает такие ништяки, как весь созданный на сегодня Java код. Язык офигенно красивый, немного перегруженный синтаксисом, и мне непонятно, как живой программист может выбрать писать на Java, когда есть Scala.
Есть привычные конструкции, типа:
1 2 |
var words = List("kung", "fu", "rocks") words.count(word => word.size > 2) //=> 2 слова? |
Есть сюрреализм:
1 2 3 |
for (url <- list) { actor { downloader ! url } } |
Надеюсь, ничего не напутал, всё-таки почти месяц прошел, но расшифровывается этот манускрипт как «для всех url принадлежащих list, отправить url загрузчику (downloader) в виде сообщения (!), и пусть он разбирается с ним в отдельном потоке (actor)». Actor-модель многопоточности через отправку сообщений мне очень понравилась. Thread’ами и Mutex’ами давно пора детей пугать, а не программировать.
Erlang
Erlang — жесточайший функциональный язык, помешанный на потоках и разделяющий мнение тов. Сталина на их судьбу — «если утонул, значит ведьма». Потоки создаются легко, убиваются легко, мониторятся и перезапускаются еще легче. Вдохновлён прологом. Местами похож на Scala (или наоборот).
Чтобы отправить сообщение потоку, нужно написать восклицательный знак:
1 |
MyProcess ! "Вот тте сообщение" . |
Чтобы описать формулу «для любого икс, принадлежащего множеству игрек, сделать множество, состоящее из квадратов икс», нужно впечатать следующее:
1 2 |
[X * 2 | X <- [1,2,3,4,5]]. %[2,4,6,8,10] |
Когда мой работодатель станет контролировать всё планету, я предложу ему перейти на Erlang, ибо надежный.
Clojure
Clojure — это LISP для Java Virtual Machine. Просто LISP. Такое ощущение, что профессиональные Java программисты в какой-то момент сильно перестают любить Java, но не деньги, поэтому создают новый нормальный язык, но на JVM, чтобы из Oracle не выгнали. Получается.
Пара примеров для тех людей, которые, видя слово LISP, думают, что кто-то написал слово SHIT четырьмя ошибками. Положить map с ключами name и profession в переменную person:
1 |
(def person {:name "Luke" :profession "President of .."}) |
Положить ссылку (не указатель) на строку «Star Wars» в переменную movie:
1 |
(def movie (ref "Star Wars")) |
И теперь добавить туда еще кусок строки, но в транзакции, чтобы параллельный поток не влез:
1 2 |
(dosync (alter movie str ": Phantom Menace")) ;"Star Wars: Phantom Menace" |
Немного жестко, да. В моём списке «выучить завтра» Clojure идет сразу после Prolog.
Haskell
Haskell — безкомпромиссный чистый функциональный язык. Я его когда-то учил, так что сюрпризов было мало. Как в любом правильном функциональном языке, в хаскеле нельзя менять значение переменных, «не равно» пишется через «/=» (выкуси, Си), а быстрая сортировка пишется в две строки:
Если коллекция пустая — забей
1 |
quicksort [] = [] |
Если не пустая, берем первый элемент x, слева приклеиваем отсортированные элементы из остатка xs, что меньше x, а справа те, что больше.
1 |
quicksort (x:xs) = quicksort [y | y <- xs, y <= x] ++ [x] ++ quicksort [y | y <- xs, y > x] |
Всё.
В общем, мозг оказался надруган, но немного вырос. Сбоку лежит следующая книга «семь баз данных за семь недель«, и я теперь очень жалею, что не купил такую же про многопоточность — «seven concurrency models in seven weeks«. После всего прочитанного, многопоточность в дот нэте выглядит как одинокий костыль с последней категорией инвалидности, и хотелось бы узнать, что творится в этом плане во взрослом мире.
Точно:
Seven Concurrency Models in Seven Weeks — вот что ещё нужно купить))