суббота, 12 марта 2011 г.

Завершение изучения Common Lisp'а

На днях закончил чтение книг Practical Common Lisp и Land of Lisp. Также, написал игру Шашки на нем, с веб-интерфейсом. Итак, к каким же я пришел выводам в завершении изучения Common Lisp'а. Хотя язык очень мощный, действительно очень мощный и гибкий. Особенно его система макросов, возможность встраивать мини-языки (eDSL). Я уже начал думать, о том, чтобы использовать его для своего следующего проекта.

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

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

В итоге, я отказался от идеи использовать его для своего коммерческого приложения. Но ни в коем случае не жалею о том, что потратил время и силы на изучение этого отличного языка.

Следующий у меня на очереди Ruby.

суббота, 12 февраля 2011 г.

Объявление и оформление функций

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

Мы много говорили о хорошем стиле, давайте теперь более конкретнее рассмотрим, что же такое хороший стиль кодирования.

  1. Весь код программы должен быть разбит на подпрограммы (функции), каждая из которых выполняет только одну цель.
  2. Все входные и выходные параметры должны быть явно описаны.
  3. Давайте функциям и переменным осмысленные названия.
  4. Код нужно писать как можно проще и понятнее.
  5. Код функций должен быть компактным, так, чтобы можно было одним взглядом охватить весь код функции.
При обучении своих учеников программированию, я использую язык Python. При этом стараюсь много чего брать из отличного учебника How to Design Programs. Например, касательно стиля кодирования, мне нравится то, как они оформляют свои функции. Перед описанием функции (и желательно до того, как мы приступим непосредственно к реализации функции) написать в виде комментария контракт, цель и пример вызова функции. Контракт описывает входные и выходные параметры функции. Указываем кратко и четко цель. А также, пример вызова функции и что должна вернуть функция при заданных входных параметрах.

В качестве примеров, приведу пару функций написанных одним из моих учеников:


# Контракт: String ~> Boolean
# Цель: Является ли переданная строка цифрой
# Пример: is_digit("1") ~> True, is_digit("123") ~> False
# is_digit("abc") ~> False
def is_digit(a):
digits = ['0','1','2','3','4','5','6','7','8','9']
if a in digits:
s = True
else:
s = False
return s


# Контракт: String ~> Boolean
# Цель: Является ли строка годом
# Пример: is_valid_year("2010") ~> True
# is_valid_year("2as2") ~> False
def is_valid_year(b):
s = False
if len(b) == 4:
if is_digit(b[0]) and is_digit(b[1]) and is_digit(b[2]) and is_digit(b[3]):
s = True
return s


Данные примеры, удовлетворяют почти всем моим правилам хорошего стиля.

четверг, 10 февраля 2011 г.

Синтаксис и семантика Лиспа


Синтаксис языка Лисп настолько прост, что некоторые обычно говорят, что у Лиспа нет синтаксиса совсем. Но лично я, с этим не соглашусь, синтаксис все же есть. Весь синтаксис Лиспа состоит из так называемых S-expressions (или иногда их называют префиксной нотацией). В общем виде, это выглядит как:


(operator arg1 arg2 arg3 ...)

То есть, сначала идет оператор, далее идут аргументы. Давайте рассмотрим простенький пример:


(+ 1 2 3)

вернет результат равный 6-ти.

Также, выражения могут быть вложены друг в друга:


(+ 1 2 (* 3 4))

вернет результат равный 15-ти.

Понятно, что каждый оператор обладает определенной семантикой. Но что делать, если нет оператора с необходимой нам семантикой? Мы можем определить свой оператор путем объявления новой функции. Допустим, нам не хватало оператора возведения числа в квадрат. Мы можем объявить свою функцию возведения в квадрат числа:


(defun sqr (a)
(* a a))

Так, мы можем объявлять свои функции. Давайте посмотрим на общий синтаксис объявления функции:


(defun name (arg1 arg2 arg3 ...)
body)


где, name - имя функции, arg1, arg2, arg3 - аргументы и body - тело функции.



В каком-то смысле, программу на Лиспе можно представить как одно очень большое s-выражение, где одни выражения вложены в другие. Но имея в своем арсенале функции мы можем сделать декомпозицию кода, то есть разбить весь код программы на небольшие функции, где каждая функция выполняет свою определенную цель.

среда, 9 февраля 2011 г.

Изучение Common Lisp'а

Изучаю по тихонечку в фоновом режиме Common Lisp. Читаю Practical Common Lisp, просто отличная книга! Язык в принципе довольно легок в изучении, начал параллельно с чтением книги писать на Лиспе небольшую игру, русские шашки, моя любимая настольная игра. Пишу пока движок, потом сделаю к нему веб-интерфейс, а потом может быть и ИИ к нему приделаю.