Почему именно функциональное программирование?
Почему Хаскель?

Содержание

У нас есть дело для вас!
Новизна
Мощь
Удовольствие
Чего ожидать от данной книги
Немного про вас
Чего ожидать от Хаскеля
В сравнении с традиционными статическими языками
В сравнении с современными динамическими языками
Хаскель в промышленности и сообществе open-source
Компиляция, отладка, и анализ производительности
Встроенные и внешние библиотеки
Краткая зарисовка истории Хаскеля
Древняя история
Ранняя античность
Современность
Ресурсы для помощи
Справочный материал
Приложения и библиотеки
Сообщество Хаскеля
Благодарности
Bryan
John
Don
Спасибо тем, кто оставлял отзывы

У нас есть дело для вас!

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

Новизна

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

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

Кроме неизменности данных, наши функции Хаскеля обычно не взаимодействуют с внешним миром; мы называем эти функции чистыми. Мы делаем строгое разделение между чистым кодом и частями наших программ, которые читают и пишут файлы, обмениваются через сеть, или двигают руками робота. Это позволяет проще организовать, объяснить, и тестировать наши программы.

Мы не применяем некоторые идеи, которые могут показаться фундаментальными, например, наличие цикла for, встроенного в язык. У нас есть другие, более гибкие способы, как сделать повторяющиеся вещи.

Даже путь, по которому мы вычисляем выражения, в Хаскеле отличается. Мы не выполняем ни одного вычисления, пока его результат не будет действительно необходим: Хаскель является языком с ленивой моделью вычислений. Эта модель - не просто издержка языка: она точно указывает, как мы пишем программы.

Мощь

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

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

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

Ленивые вычисления имеют некоторые жуткие эффекты. Например, давайте попробуем найти k наименьших элементов несортированного списка. В традиционном языке, очевидным подходом будет отсортировать список и взять первые k элементов, но это долго. Для эффективности, мы напишем специальную функцию, которая получит все эти значения за один проход, но ей придется выполнять некоторую умеренно-сложную бухгалтерию. В Хаскеле, подход "отсортировать и взять" действительно работает хорошо: лень удостоверится, что список отсортирован настолько, чтобы найти k минимальных элементов.

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

-- file: ch00/KMinima.hs
-- lines beginning with "--" are comments.

minima k xs = take k (sort xs)
Может потребоваться некоторое время, чтобы у вас появилось интуитивное чувство того, когда именно важны ленивые вычисления, но когда мы пользуемся ими, то получающийся код часто получается чистым, кратким и эффективным.

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

Удовольствие

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

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

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

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

Более того, мы не собираемся ставить "кирпичных стен" перед вами: в данной книге нет особенно сложных и ужасных техник, которые вы должны выучить, чтобы научиться эффективно программировать.

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

Чего ожидать от данной книги

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

В данной книге мы покажем вам, как использовать функциональное программирование и Хаскель для решения реалистичных проблем. Это практическая книга: каждая глава содержит большое число кода, а многие главы содержат готовые приложения. Есть несколько примеров библиотек, техник и инструментов, которые мы разработаем.
  • Создадим приложение, которое скачивает эпизоды подкаста из Интернет и сохраняет историю в базе данных SQL
  • Протестируем ваш код в интуитивной и мощной манере. Опишем свойства, которые должны быть истинны, затем позволим библиотеке QuickCheck сгенерировать самостоятельно тестовые случаи.
  • Получим снимок штрихкода низкого разрешения с камеры телефона и преобразуем его в индентификатор, который вы можете использовать для запроса к библиотеке или к сайту книжного магазина.
  • Напишем код, который работает в Web. Обменивайтесь данными с серверами и клиентами, написанными на других языках, используя JSON-нотацию. Разработаем программу для параллельной проверки линков.

Немного про вас

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

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

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

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

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

Чего ожидать от Хаскеля

Хаскель - это язык программирования общего назначения. Он был разработан не для какой-то определенной "ниши". Хотя он имеет сильные требования по тому, как надо писать программы, он не дает преимуществ одним видам проблем над другими.

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

В сравнении с традиционными статическими языками

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

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

С учетом некоторых других возможностей Хаскеля можно еще более увеличить объем работы, которую можно поместить в объем одного экрана. Это дает улучшения во времени разработки и ловкости: мы можем создавать надежный код быстро, и легко переделывать его в ответ на изменение требований.

Иногда, программы на Хаскеле могут работать более медленно, чем похожие программы, написанные на C или C++. Для большинства написанного нами кода, большие преимущества в производительности и надежности, предоставляемые Хаскелем, перевешивают любые небольшие недостатки в производительности.

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

В сравнении с современными динамическими языками

За прошедшее десятилетие, интерпретируемые языки с динамическими типами становились все более популярными. Они дают существенную выгоду в продуктивности разработчика. Хотя это часто дается падением производительности, для многих задач программирования, продуктивность важнее производительности, или производительность не является важным фактором в любом случае.

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

Если мы принимаем во внимание производительность, Хаскель почти всегда имеет большое преимущество. Код, скомпилированный Glasgow Haskell Compiler (GHC) обычно от 20 до 60 раз превосходит по скорости код, который работает через интерпретатор динамического языка программирования. GHC также имеет интерпретатор, так что вы можете выполнять скрипты, не компилируя их.

Другое большое различие между языками с динамическими типами и Хаскелем лежит в их философии относительно типов. Главной причиной популярности языков с динамическими типами является то, что только редко нам нужно точно описывать типы. Через патоматический вывод типов, Хаскель дает нам то же преимущество.

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

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

Конечно, у нас есть свои мнения о том, какие компромисы более выгодны. Двое из нас уже имеют годы опыта в программировании на языках с динамическими типами. Нам они нравятся, мы все еще используем их каждый день; но обычно мы предпочитаем Хаскель.

Хаскель в промышленности и сообществе open-source

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

  • Программы разработки ASIC и FPGA (Lava, продукты Bluespec Inc.)
  • Программы для написания музыки (Haskore)
  • Компиляторы и относящиеся к ним инструменты (самый известный - это GHC)
  • Распределенная система контроля версий (Darcs)
  • Промежуточные программы для Web (HAppS, продукты от Galois Inc.)
Ниже приведен список некоторых компаний, использующих Хаскель в конце 2008 года, взятый из Вики Хаскеля.
  • ABN AMRO - интернациональный банк. Он использует Хаскель в инвестиционной финансовой деятельности, для оценки риска контрагента на потфелях финансовых деривативов.
  • Anygma это "стартаповая" компания. Она разрабатывает устройства создания мультимедийного контента, используя Хаскель.
  • Amgen - компания, связанная с биотехнологией. Она создает математические модели и другие комплексные приложения на Хаскеле.
  • Bluespec - это компания, создающая программное обеспечения для создания ASIC и FPGA. Ее продукты разработаны на Хаскеле, а языки для разработки микросхем, которые есть в этих продуктах, несут в себе большое влияние Хаскеля.
  • Eaton использует Хаскель для разработки и проверки гидравлических систем гибридных транспортных средств.

Компиляция, отладка, и анализ производительности

Для практической работы, кроме самого языка, важна также экосистема библиотек и программ вокруг него. Хаскель очень развит в этом отношении.

Самый часто используемый компилятор, GHC, активно разрабатывался более 15 лет и представляет собой зрелый и стабильный набор возможностей:
  • Программа компилируется в эффективный нативный код на всех основных современных операционных системах и архитектурах ЦП.
  • Быстрое внедрение скомпилированных программ, неотягощенное ограничениями лицензий.
  • Анализ покрытия кода
  • Детальный профайлинг производительности и использования памяти
  • Тщательная документация
  • Мощная масштабируемая поддержка параллельного и многоядерного программирования
  • Интерактивный интерпретатор и отладчик

Встроенные и внешние библиотеки

Компилятор GHC поставляется с коллекцией полезных библиотек. Ниже приведены некоторые частые случаи в программировании, для которых предназначены эти библиотеки.

  • Файловый ввод вывод, перемещение по файловой системе и манипуляция ей
  • Программирования сетевого клиента и сервера
  • Регулярные выражения и парсинг
  • Параллельное программирование
  • Автоматическое тестирование
  • Звуки и графика
База данных пакетов Хаскеля - это коллекция библиотек и приложений сообщества Хаскель с открытым исходным кодом. Большинство библиотек, находящихся на Hackage лицензированы под достаточно либеральными лицензиями, позволяющими как коммерческое использование, так и использование с открытым исходным кодом. Некоторые области, для которых есть библиотеки, приведены ниже:
  • Интерфейсы ко всем основным коммерческим базам данных и базам данных с открытыми исходными кодами
  • Обработка XML, HTML, и XQuery
  • Разработка сетевых приложений, клиентов и серверов
  • GUI, включая кросс-платформенные решения
  • Поддержка UNICODE и других текстовых кодировок

A brief sketch of Haskell's history

The development of Haskell is rooted in mathematics and computer science research. 1 comment

Prehistory

A few decades before modern computers were invented, the mathematician Alonzo Church developed a language called the lambda calculus. He intended it as a tool for investigating the foundations of mathematics. The first person to realize the practical connection between programming and the lambda calculus was John McCarthy, who created Lisp in 1958. 6 comments

During the 1960s, computer scientists began to recognise and study the importance of the lambda calculus. Peter Landin and Christopher Strachey developed ideas about the foundations of programming languages: how to reason about what they do (operational semantics) and how to understand what they mean (denotational semantics). 1 comment

In the early 1970s, Robin Milner created a more rigorous functional programming language named ML. While ML was developed to help with automated proofs of mathematical theorems, it gained a following for more general computing tasks. 1 comment

The 1970s saw the emergence of lazy evaluation as a novel strategy. David Turner developed SASL and KRC, while Rod Burstall and John Darlington developed NPL and Hope. NPL, KRC and ML influenced the development of several more languages in the 1980s, including Lazy ML, Clean, and Miranda. 4 comments

Early antiquity

By the late 1980s, the efforts of researchers working on lazy functional languages were scattered across more than a dozen languages. Concerned by this diffusion of effort, a number of researchers decided to form a committee to design a common language. After three years of work, the committee published the Haskell 1.0 specification in 1990. It named the language after Haskell Curry, an influential logician. 1 comment

Many people are rightfully suspicious of “design by committee”, but the work of the Haskell committee is a beautiful example of the best work a committee can do. They produced an elegant, considered language design, and succeeded in unifying the fractured efforts of their research community. Of the thicket of lazy functional languages that existed in 1990, only Haskell is still actively used. 11 comments

Since its publication in 1990, the Haskell language standard has seen five revisions, most recently in 1998. A number of Haskell implementations have been written, and several are still actively developed. 6 comments

During the 1990s, Haskell served two main purposes. On one side, it gave language researchers a stable language in which to experiment with making lazy functional programs run efficiently. Other researchers explored how to construct programs using lazy functional techniques. Still others used it as a teaching language. 4 comments

The modern era

While these basic explorations of the 1990s proceeded, Haskell remained firmly an academic affair. The informal slogan of those inside the community was to “avoid success at all costs”. Few outsiders had heard of the language at all. Indeed, functional programming as a field was quite obscure. 3 comments

During this time, the mainstream programming world experimented with relatively small tweaks: from programming in C, to C++, to Java. Meanwhile, on the fringes, programmers were beginning to tinker with new, more dynamic languages. Guido van Rossum designed Python; Larry Wall created Perl; and Yukihiro Matsumoto developed Ruby. 10 comments

As these newer languages began to seep into wider use, they spread some crucial ideas. The first was that programmers are not merely capable of working in expressive languages; in fact, they flourish. The second was in part a byproduct of the rapid growth in raw computing power of that era: it's often smart to sacrifice some execution performance in exchange for a big increase in programmer productivity. Finally, several of these languages borrowed from functional programming. 4 comments

Over the past half a decade, Haskell has successfully escaped from academia, buoyed in part by the visibility of Python, Ruby, and even Javascript. The language now has a vibrant and fast-growing culture of open source and commercial users, and researchers continue to use it to push the boundaries of performance and expressiveness. 10 comments

Helpful resources

As you work with Haskell, you're sure to have questions and want more information about things. Here are some Internet resources where you can look up information and interact with other Haskell programmers. 1 comment

Reference material

  • The Haskell Hierarchical Libraries reference provides the documentation for the standard library that comes with your compiler. This is one of the most valuable online assets for Haskell programmers. 3 comments

  • For questions about language syntax and features, the Haskell 98 Report describes the Haskell 98 language standard. No comments

  • Various extensions to the language have become commonplace since the Haskell 98 Report was released. The GHC Users's Guide contains detailed documentation on the extensions supported by GHC, as well as some GHC-specific features. 1 comment

  • Hoogle and Hayoo are Haskell API search engines. They can search for functions by name or by type. 1 comment

Applications and libraries

If you're looking for a Haskell library to use for a particular task, or an application written in Haskell, check out the following resources. 1 comment

  • The Haskell community maintains a central repository of open source Haskell libraries and applications. It's called Hackage, and it lets you search for software to download, or browse its collection by category. No comments

  • The Haskell Wiki contains a section dedicated to information about particular Haskell libraries. No comments

The Haskell community

There are a number of ways you can get in touch with other Haskell programmers, to ask questions, learn what other people are talking about, and simply do some social networking with your peers. No comments

  • The first stop on your search for community resources should be the Haskell web site. This page contains the most current links to various communities and information, as well as a huge and actively maintained wiki. No comments

  • Haskellers use a number of mailing lists for topical discussions. Of these, the most generally interesting is named haskell-cafe. It has a relaxed, friendly atmosphere, where professionals and academics rub shoulders with casual hackers and beginners. 1 comment

  • For real-time chat, the Haskell IRC channel, named #haskell, is large and lively. Like haskell-cafe, the atmosphere stays friendly and helpful in spite of the huge number of concurrent users. 3 comments

  • There are many local user groups, meetups, academic workshops, and the like; here is a list of the known user groups and workshops. No comments

  • The Haskell Weekly News is a very-nearly-weekly summary of activities in the Haskell community. You can find pointers to interesting mailing list discussions, new software releases, and the like. 3 comments

  • The Haskell Communities and Activities Report collects information about people that use Haskell, and what they are doing with it. It has been running for years, so it provides a good way to peer into Haskell's past. 1 comment

Acknowledgments

This book would not exist without the Haskell community: an anarchic, hopeful cabal of artists, theoreticians and engineers, who for twenty years have worked to create a better, bug-free programming world. The people of the Haskell community are unique in their combination of friendliness and intellectual depth. No comments

We wish to thank our editor, Mike Loukides, and the production team at O'Reilly for all of their advice and assistance. No comments

Bryan

I had a great deal of fun working with John and Don. Their independence, good nature, and formidable talent made the writing process remarkably smooth. No comments

Simon Peyton Jones took a chance on a college student who emailed him out of the blue in early 1994. Interning for him over that summer remains a highlight of my professional life. With his generosity, boundless energy, and drive to collaborate, he inspires the whole Haskell community. No comments

My children, Cian and Ruairi, always stood ready to help me to unwind with wonderful, madcap little-boy games. No comments

Finally, of course, I owe a great debt to my wife, Shannon, for her love, wisdom, and support during the long gestation of this book. No comments

John

I am so glad to be able to work with Bryan and Don on this project. The depth of their Haskell knowledge and experience is amazing. I enjoyed finally being able to have the three of us sit down in the same room -- over a year after we started writing. No comments

My 2-year-old Jacob, who decided that it would be fun to use a keyboard too, and is always eager to have me take a break from the computer and help him make some fun typing noises on a 50-year-old Underwood typewriter. No comments

Most importantly, I wouldn't have ever been involved in this project without the love, support, and encouragement from my wife, Terah. No comments

Don

Before all else, I'd like to thank my amazing co-conspirators, John and Bryan, for encouragment, advice and motivation. No comments

My colleagues at Galois, Inc., who daily wield Haskell in the real world, provided regular feedback and war stories, and helped ensured a steady supply of espresso. 1 comment

My PhD supervisor, Manuel Chakravarty, and the PLS research group, who provided encouragement, vision and energy, and showed me that a rigorous, foundational approach to programming can make the impossible happen. No comments

And, finally, thanks to Suzie, for her insight, patience and love. No comments

Thank you to our reviewers

We developed this book in the open, posting drafts of chapters to our web site as we completed them. Readers then submitted feedback using a web application that we developed. By the time we finished writing the book, about 800 people had submitted over 7,500 comments, an astounding figure. 1 comment

We deeply appreciate the time that so many people volunteered to help us to improve our book. Their encouragement and enthusiasm over the 15 months we spent writing made the process a pleasure. No comments

The breadth and depth of the comments we received have profoundly improved the quality of this book. Nevertheless, all errors and omissions are, of course, ours. 1 comment

The following people each contributed over 1% of the total number of review comments that we received. We would like to thank them for their care in providing us with so much detailed feedback. No comments

Alex Stangl, Andrew Bromage, Brent Yorgey, Bruce Turner, Calvin Smith, David Teller, Henry Lenzi, Jay Scott, John Dorsey, Justin Dressel, Lauri Pesonen, Lennart Augustsson, Luc Duponcheel, Matt Hellige, Michael T. Richter, Peter McLain, Rob deFriesse, RГјdiger Hanke, Tim Chevalier, Tim Stewart, William N. Halchin. No comments

We are also grateful to the people below, each of whom contributed at least 0.2% of all comments. No comments

Achim Schneider, Adam Jones, Alexander Semenov, Andrew Wagner, Arnar Birgisson, Arthur van Leeuwen, Bartek Ćwikłowski, Bas Kok, Ben Franksen, Björn Buckwalter, Brian Brunswick, Bryn Keller, Chris Holliday, Chris Smith, Dan Scott, Dan Weston, Daniel Larsson, Davide Marchignoli, Derek Elkins, Dirk Ullrich, Doug Kirk, Douglas Silas, Emmanuel Delaborde, Eric Lavigne, Erik Haugen, Erik Jones, Fred Ross, Geoff King, George Moschovitis, Hans van Thiel, Ionuț Arțăriși, Isaac Dupree, Isaac Freeman, Jared Updike, Joe Thornber, Joeri van Eekelen, Joey Hess, Johan Tibell, John Lenz, Josef Svenningsson, Joseph Garvin, Josh Szepietowski, Justin Bailey, Kai Gellien, Kevin Watters, Konrad Hinsen, Lally Singh, Lee Duhem, Luke Palmer, Magnus Therning, Marc DeRosa, Marcus Eskilsson, Mark Lee Smith, Matthew Danish, Matthew Manela, Michael Vanier, Mike Brauwerman, Neil Mitchell, Nick Seow, Pat Rondon, Raynor Vliegendhart, Richard Smith, Runar Bjarnason, Ryan W. Porter, Salvatore Insalaco, Sean Brewer, Sebastian Sylvan, Sebastien Bocq, Sengan Baring-Gould, Serge Le Huitouze, Shahbaz Chaudhary, Shawn M Moore, Tom Tschetter, Valery V. Vorotyntsev, Will Newton, Wolfgang Meyer, Wouter Swierstra. 1 comment

We would like to acknowledge the following people, many of whom submitted a number of comments. 1 comment

Aaron Hall, Abhishek Dasgupta, Adam Copp, Adam Langley, Adam Warrington, Adam Winiecki, Aditya Mahajan, Adolfo Builes, Al Hoang, Alan Hawkins, Albert Brown, Alec Berryman, Alejandro Dubrovsky, Alex Hirzel, Alex Rudnick, Alex Young, Alexander Battisti, Alexander Macdonald, Alexander Strange, Alf Richter, Alistair Bayley, Allan Clark, Allan Erskine, Allen Gooch, Andre Nathan, Andreas Bernstein, Andreas Schropp, Andrei Formiga, Andrew Butterfield, Andrew Calleja, Andrew Rimes, Andrew The, Andy Carson, Andy Payne, Angelos Sphyris, Ankur Sethi, António Pedro Cunha, Anthony Moralez, Antoine Hersen, Antoine Latter, Antoine S., Antonio Cangiano, Antonio Piccolboni, Antonios Antoniadis, Antonis Antoniadis, Aristotle Pagaltzis, Arjen van Schie, Artyom Shalkhakov, Ash Logan, Austin Seipp, Avik Das, Avinash Meetoo, BVK Chaitanya, Babu Srinivasan, Barry Gaunt, Bas van Dijk, Ben Burdette, Ben Ellis, Ben Moseley, Ben Sinclair, Benedikt Huber, Benjamin Terry, Benoit Jauvin-Girard, Bernie Pope, Björn Edström, Bob Holness, Bobby Moretti, Boyd Adamson, Brad Ediger, Bradley Unterrheiner, Brendan J. Overdiep, Brendan Macmillan, Brett Morgan, Brian Bloniarz, Brian Lewis, Brian Palmer, Brice Lin, C Russell, Cale Gibbard, Carlos Aya, Chad Scherrer, Chaddaï Fouché, Chance Coble, Charles Krohn, Charlie Paucard, Chen Yufei, Cheng Wei, Chip Grandits, Chris Ball, Chris Brew, Chris Czub, Chris Gallagher, Chris Jenkins, Chris Kuklewicz, Chris Wright, Christian Lasarczyk, Christian Vest Hansen, Christophe Poucet, Chung-chieh Shan, Conal Elliott, Conor McBride, Conrad Parker, Cosmo Kastemaa, Creighton Hogg, Crutcher Dunnavant, Curtis Warren, D Hardman, Dafydd Harries, Dale Jordan, Dan Doel, Dan Dyer, Dan Grover, Dan Orias, Dan Schmidt, Dan Zwell, Daniel Chicayban Bastos, Daniel Karch, Daniel Lyons, Daniel Patterson, Daniel Wagner, Daniil Elovkov, Danny Yoo, Darren Mutz, Darrin Thompson, Dave Bayer, Dave Hinton, Dave Leimbach, Dave Peterson, Dave Ward, David Altenburg, David B. Wildgoose, David Carter, David Einstein, David Ellis, David Fox, David Frey, David Goodlad, David Mathers, David McBride, David Sabel, Dean Pucsek, Denis Bueno, Denis Volk, Devin Mullins, Diego Moya, Dino Morelli, Dirk Markert, Dmitry Astapov, Dougal Stanton, Dr Bean, Drew Smathers, Duane Johnson, Durward McDonell, E. Jones, Edwin DeNicholas, Emre Sevinc, Eric Aguiar, Eric Frey, Eric Kidd, Eric Kow, Eric Schwartz, Erik Hesselink, Erling Alf, Eruc Frey, Eugene Grigoriev, Eugene Kirpichov, Evan Farrer, Evan Klitzke, Evan Martin, Fawzi Mohamed, Filippo Tampieri, Florent Becker, Frank Berthold, Fred Rotbart, Frederick Ross, Friedrich Dominicus, Gal Amram, Ganesh Sittampalam, Gen Zhang, Geoffrey King, George Bunyan, George Rogers, German Vidal, Gilson Silveira, Gleb Alexeyev, Glenn Ehrlich, Graham Fawcett, Graham Lowe, Greg Bacon, Greg Chrystall, Greg Steuck, Grzegorz Chrupała, Guillaume Marceau, Haggai Eran, Harald Armin Massa, Henning Hasemann, Henry Laxen, Hitesh Jasani, Howard B. Golden, Ilmari Vacklin, Imam Tashdid ul Alam, Ivan Lazar Miljenovic, Ivan Miljenovic, J. Pablo Fernández, J.A. Zaratiegui, Jaap Weel, Jacques Richer, Jake McArthur, Jake Poznanski, Jakub Kotowski, Jakub Labath, James Cunningham, James Smith, Jamie Brandon, Jan Sabbe, Jared Roberts, Jason Dusek, Jason F, Jason Kikel, Jason Mobarak, Jason Morton, Jason Rogers, Jeff Balogh, Jeff Caldwell, Jeff Petkau, Jeffrey Bolden, Jeremy Crosbie, Jeremy Fitzhardinge, Jeremy O'Donoghue, Jeroen Pulles, Jim Apple, Jim Crayne, Jim Snow, Joan Jiménez, Joe Fredette, Joe Healy, Joel Lathrop, Joeri Samson, Johannes Laire, John Cowan, John Doe, John Hamilton, John Hornbeck, John Lien, John Stracke, Jonathan Guitton, Joseph Bruce, Joseph H. Buehler, Josh Goldfoot, Josh Lee, Josh Stone, Judah Jacobson, Justin George, Justin Goguen, Kamal Al-Marhubi, Kamil Dworakowski, Keegan Carruthers-Smith, Keith Fahlgren, Keith Willoughby, Ken Allen, Ken Shirriff, Kent Hunter, Kevin Hely, Kevin Scaldeferri, Kingdon Barrett, Kristjan Kannike, Kurt Jung, Lanny Ripple, Laurențiu Nicola, Laurie Cheers, Lennart Kolmodin, Liam Groener, Lin Sun, Lionel Barret de Nazaris, Loup Vaillant, Luke Plant, Lutz Donnerhacke, Maarten Hazewinkel, Malcolm Reynolds, Marco Piccioni, Mark Hahnenberg, Mark Woodward, Marko Tosic, Markus Schnell, Martijn van Egdom, Martin Bayer, Martin DeMello, Martin Dybdal, Martin Geisler, Martin Grabmueller, Matúš Tejiščák, Mathew Manela, Matt Brandt, Matt Russell, Matt Trinneer, Matti Niemenmaa, Matti Nykänen, Max Cantor, Maxime Henrion, Michael Albert, Michael Brauwerman, Michael Campbell, Michael Chermside, Michael Cook, Michael Dougherty, Michael Feathers, Michael Grinder, Michael Kagalenko, Michael Kaplan, Michael Orlitzky, Michael Smith, Michael Stone, Michael Walter, Michel Salim, Mikael Vejdemo Johansson, Mike Coleman, Mike Depot, Mike Tremoulet, Mike Vanier, Mirko Rahn, Miron Brezuleanu, Morten Andersen, Nathan Bronson, Nathan Stien, Naveen Nathan, Neil Bartlett, Neil Whitaker, Nick Gibson, Nick Messenger, Nick Okasinski, Nicola Paolucci, Nicolas Frisby, Niels Aan de Brugh, Niels Holmgaard Andersen, Nima Negahban, Olaf Leidinger, Oleg Anashkin, Oleg Dopertchouk, Oleg Taykalo, Oliver Charles, Olivier Boudry, Omar Antolín Camarena, Parnell Flynn, Patrick Carlisle, Paul Brown, Paul Delhanty, Paul Johnson, Paul Lotti, Paul Moore, Paul Stanley, Paulo Tanimoto, Per Vognsen, Pete Kazmier, Peter Aarestad, Peter Ipacs, Peter Kovaliov, Peter Merel, Peter Seibel, Peter Sumskas, Phil Armstrong, Philip Armstrong, Philip Craig, Philip Neustrom, Philip Turnbull, Piers Harding, Piet Delport, Pragya Agarwal, Raúl Gutiérrez, Rafael Alemida, Rajesh Krishnan, Ralph Glass, Rauli Ruohonen, Ravi Nanavati, Raymond Pasco, Reid Barton, Reto Kramer, Reza Ziaei, Rhys Ulerich, Ricardo Herrmann, Richard Harris, Richard Warburton, Rick van Hattem, Rob Grainger, Robbie Kop, Rogan Creswick, Roman Gonzalez, Rory Winston, Ruediger Hanke, Rusty Mellinger, Ryan Grant, Ryan Ingram, Ryan Janzen, Ryan Kaulakis, Ryan Stutsman, Ryan T. Mulligan, S Pai, Sam Lee, Sandy Nicholson, Scott Brickner, Scott Rankin, Scott Ribe, Sean Cross, Sean Leather, Sergei Trofimovich, Sergio Urinovsky, Seth Gordon, Seth Tisue, Shawn Boyette, Simon Brenner, Simon Farnsworth, Simon Marlow, Simon Meier, Simon Morgan, Sriram Srinivasan, Sriram Srinivasan, Stefan Aeschbacher, Stefan Muenzel, Stephan Friedrichs, Stephan Nies, Stephan-A. Posselt, Stephyn Butcher, Steven Ashley, Stuart Dootson, Terry Michaels, Thomas Cellerier, Thomas Fuhrmann, Thomas Hunger, Thomas M. DuBuisson, Thomas Moertel, Thomas Schilling, Thorsten Seitz, Tibor Simic, Tilo Wiklund, Tim Clark, Tim Eves, Tim Massingham, Tim Rakowski, Tim Wiess, Timo B. Hübel, Timothy Fitz, Tom Moertel, Tomáš Janoušek, Tony Colston, Travis B. Hartwell, Tristan Allwood, Tristan Seligmann, Tristram Brelstaff, Vesa Kaihlavirta, Victor Nazarov, Ville Aine, Vincent Foley, Vipul Ved Prakash, Vlad Skvortsov, Vojtěch Fried, Wei Cheng, Wei Hu, Will Barrett, Will Farr, Will Leinweber, Will Robertson, Will Thompson, Wirt Wolff, Wolfgang Jeltsch, Yuval Kogman, Zach Kozatek, Zachary Smestad, Zohar Kelrich. 3 comments

Finally, we wish to thank those readers who submitted over 800 comments anonymously. 4 comments

Want to stay up to date? Subscribe to the comment feed for this chapter, or the entire book.

Copyright 2007, 2008 Bryan O'Sullivan, Don Stewart, and John Goerzen. This work is licensed under a Creative Commons Attribution-Noncommercial 3.0 License. Icons by Paul Davey aka Mattahan.

Хостинг от uCoz