Сначала введение: что такое Haskell? Haskell - это ленивый чисто функциональный язык программирования.

Что это теперь?

Что ж, ленивый означает, что Haskell не будет выполнять ваши команды сразу, а будет ждать, пока вам не понадобится результат. Поначалу это может показаться странным, но в нем есть довольно приятные функции, например бесконечные списки:

evenNumbers = [0, 2..]

Этот фрагмент объявит массив, содержащий все четные числа. Но, как мы уже говорили, Haskell ленив, поэтому он ничего не будет вычислять, пока не будет вынужден это сделать.

take 10 evenNumbers

Код возвращает первые 10 элементов четного числа, поэтому Haskell вычислит только их.

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

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

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

Математика, рекурсия и Haskell входят в панель

Я бы также добавил, что Haskell действительно похож на математику. Я объяснюсь на примере: последовательность Фибоначчи.

Как видите, определения очень похожи. Вы можете сказать, что это слишком похоже.

Так где же петли?

Они вам не нужны! Эти четыре линии - все, что требуется в Haskell для вычисления последовательности Фибоначчи. Это почти тривиально. Это рекурсивное определение, означающее, что функция вызывает сама себя. Для понимания, вот пример рекурсивной функции:

factorial :: (Integral a) => a -> a
factorial 0 = 1
factorial x = x * factorial (x-1)

Вот что делает компьютер при вычислении call факториала 5:

factorial 5 = 5 * factorial 4
factorial 4 = 4 * factorial 3
factorial 3 = 3 * factorial 2
factorial 2 = 2 * factorial 1
factorial 1 = 1 * factorial 0
factorial 0 = 1
factorial 1 = 1 * 1 = 1
factorial 2 = 2 * 1 = 2
factorial 3 = 3 * 2 = 6
factorial 4 = 4 * 6 = 24
factorial 5 = 5 * 24 = 120

Вы можете подумать, что такой подход неэффективен, но это неправда. С некоторой осторожностью вы можете достичь C-подобной скорости, иногда даже немного лучше (см. Этот поток stackoverflow для получения дополнительной информации).

Подождите! Вы сказали, что нет переменных?

Да, в Haskell нет переменных - только константы. Хорошо, теоретически в Haskell есть переменные. Но вы ими пользуетесь редко.

Как это может быть? Вы не можете кодировать без переменных, это безумие!

Что ж, большинство языков обязательны. Это означает, что большая часть кода направлена ​​на объяснение компьютеру, как выполнить какую-либо задачу. С другой стороны, Haskell декларативен. Таким образом, большая часть вашего кода направлена ​​на определение желаемого результата (константы ≈ определения). Тогда компилятор разберется, как это сделать.

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

Система типов (нет, я не буду вдаваться в дебаты о статике и динамике)

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

data Hand = Left | Right

Мы только что определили тип данных Hand, который может принимать значение Left или Right. Но давайте посмотрим на более сложный пример:

data BinTree = Empty
          | Leaf Int
          | Node BinTree BinTree

Мы определяем двоичное дерево, используя рекурсивный тип. Определения типов могут быть рекурсивными!

Хорошо, я понял: Haskell потрясающий