Перейти до вмісту

Haskell

Матеріал з K2 ERP Wiki Ukraine — База знань з автоматизації та санкцій в Україні
Версія від 20:29, 8 травня 2026, створена R (обговорення | внесок) (Створена сторінка: {{SEO|title=Haskell — функціональна мова програмування, чисті функції, типи, монади, lazy evaluation, GHC, Cabal, Stack і безпечна архітектура|description=Haskell — Wiki-стаття про чисту функціональну мову програмування Haskell. Розглянуто pure functions, immutability, lazy evaluation, referential transparency, algebraic data ty...)
(різн.) ← Попередня версія | Поточна версія (різн.) | Новіша версія → (різн.)

SEO title: Haskell — функціональна мова програмування, чисті функції, типи, монади, lazy evaluation, GHC, Cabal, Stack і безпечна архітектура SEO description: Haskell — Wiki-стаття про чисту функціональну мову програмування Haskell. Розглянуто pure functions, immutability, lazy evaluation, referential transparency, algebraic data types, pattern matching, type classes, monads, functors, applicatives, GHC, GHCi, Cabal, Stack, GHCup, Haskell Language Server, Hackage, Stackage, тестування, QuickCheck, property-based testing, web/backend, компіляцію, продуктивність, обмеження, практичне використання та місце Haskell у сучасній розробці. SEO keywords: Haskell, функціональне програмування, functional programming, pure functions, immutability, lazy evaluation, referential transparency, algebraic data types, pattern matching, type classes, monads, functor, applicative, GHC, GHC 9.14, GHC 9.12, Cabal, Stack, GHCup, Haskell Language Server, Hackage, Stackage, QuickCheck, property based testing, Haskell backend, Haskell web, typed functional programming, програмування Haskell Alternative to: імперативне програмування зі станом всюди; runtime-помилки через слабку типізацію; бізнес-логіка без математичної моделі; код без referential transparency; складні side effects без контролю; тестування лише прикладами без property-based testing; архітектура без сильних типів; обробка помилок через неявні exceptions


Haskell — це чиста функціональна мова програмування зі статичною типізацією, lazy evaluation, immutable data, algebraic data types, pattern matching, type classes і сильним акцентом на математичну коректність програм.

Haskell часто використовують для навчання функціональному мисленню, компіляторів, формальних моделей, financial systems, backend-сервісів, DSL, research, high-assurance code, parserів, складної бізнес-логіки й задач, де типи можуть запобігти великій кількості помилок.

Коротко: Haskell — це мова, де функції чисті, дані immutable, типи дуже сильні, а side effects явно контролюються. Вона вимагає іншого мислення, але допомагає писати дуже передбачуваний код.

Офіційна сторінка Haskell описує мову як purely functional programming language із referential transparency, immutability і lazy evaluation. [1]

Головна ідея

Головна ідея Haskell — будувати програми як композицію чистих функцій і точно описаних типів.

У звичайному імперативному стилі програма часто змінює стан:

  • змінні перезаписуються;
  • об’єкти мутують;
  • функції можуть змінювати глобальні дані;
  • side effects приховані;
  • порядок виконання дуже важливий.

У Haskell підхід інший:

  • значення immutable;
  • функції не змінюють світ без явного типу;
  • типи описують можливі стани;
  • багато помилок ловить компілятор;
  • програма будується через композицію функцій.

Проста аналогія: Haskell змушує спочатку чітко описати “які значення можливі”, а вже потім писати код. Це схоже на креслення перед будівництвом, а не ремонт під час руху.

Актуальний стан інструментів

Станом на травень 2026 року офіційна сторінка GHC показує серед останніх релізів GHC 9.12.4 від 27 березня 2026 року і GHC 9.14.1 від 19 грудня 2025 року. [2]

Офіційна сторінка Haskell Downloads рекомендує встановлювати Haskell через GHCup, який може встановити GHC, cabal-install, Stack і Haskell Language Server. [3]

GHC також запровадив LTS-підхід: Haskell.org повідомляв, що GHC починає підтримувати LTS release/branch із довшим періодом підтримки, орієнтовно від двох до трьох років. [4]

Для документації: у Haskell-проєктах важливо фіксувати версії GHC, Cabal/Stack і package set. Різні версії compiler і dependencies можуть суттєво впливати на build.

GHC

GHC або Glasgow Haskell Compiler — головний компілятор Haskell.

GHC включає:

  • compiler;
  • runtime system;
  • GHCi;
  • optimizer;
  • extensions;
  • profiling support;
  • documentation;
  • libraries;
  • package support.

GHC є фактичним стандартом для сучасного Haskell.

Офіційна сторінка GHC описує його як state-of-the-art open source compiler and interactive environment for Haskell. [5]

GHCi

GHCi — інтерактивне середовище Haskell.

Приклад:

ghci
Prelude> 2 + 3
5
Prelude> map (*2) [1,2,3]
[2,4,6]

GHCi корисний для:

  • навчання;
  • швидкої перевірки functions;
  • type exploration;
  • debugging;
  • prototyping;
  • REPL workflow.

GHCup

GHCup — рекомендований installer і manager для Haskell toolchain.

Через GHCup можна встановлювати:

  • GHC;
  • cabal-install;
  • Stack;
  • Haskell Language Server.

Офіційна сторінка Haskell Downloads прямо рекомендує GHCup для Linux, macOS, FreeBSD, Windows або WSL2. [6]

Cabal

Cabal — build system і package description format для Haskell.

Cabal використовується для:

  • опису packages;
  • builds;
  • dependencies;
  • tests;
  • benchmarks;
  • library/executable targets;
  • Hackage packages.

Типові команди:

cabal update
cabal build
cabal test
cabal run

Haskell documentation page містить Cabal User Guide серед основних довідників Haskell tooling. [7]

Stack

Stack — альтернативний build tool для Haskell.

Stack фокусується на reproducible builds і curated package sets через Stackage.

Документація Stack описує, що Stack керує GHC installations і автоматично вибирає потрібну версію GHC для проєкту. [8]

Типові команди:

stack new my-project
stack build
stack test
stack run

Haskell Language Server

Haskell Language Server або HLS — language server для редакторів.

Він дає:

  • автодоповнення;
  • diagnostics;
  • go to definition;
  • hover info;
  • code actions;
  • formatting;
  • type information;
  • інтеграцію з VS Code, Vim, Emacs та іншими редакторами.

Haskell Language Server releases підтримують конкретні версії GHC, тому сумісність HLS і GHC потрібно перевіряти. [9]

Hackage

Hackage — центральний repository Haskell packages.

Там публікуються libraries і tools.

Hackage корисний для:

  • пошуку libraries;
  • перегляду package documentation;
  • version history;
  • dependencies;
  • maintainers;
  • source tarballs.

Перед використанням package варто перевіряти maintenance, compatibility, license і recent releases.

Stackage

Stackage — curated package set для Haskell.

Ідея Stackage — мати набір package versions, які разом проходять build.

Це допомагає зменшити dependency conflicts.

Stackage має:

  • LTS snapshots;
  • nightly snapshots;
  • GHC version binding;
  • curated ecosystem.

Наприклад, Stackage Nightly 2026-05-06 використовував GHC 9.12.4. [10]

Чиста функція

Чиста функція — функція, яка:

  • для однакових inputs завжди повертає однаковий output;
  • не змінює зовнішній стан;
  • не має прихованих side effects.

Приклад:

add :: Int -> Int -> Int
add a b = a + b

Ця функція чиста: вона лише обчислює суму.

Referential transparency

Referential transparency означає, що expression можна замінити його значенням без зміни поведінки програми.

Наприклад:

add 2 3

можна замінити на:

5

Це робить код передбачуванішим і полегшує reasoning.

Офіційна сторінка Haskell називає referential transparency однією з ключових властивостей мови. [11]

Immutability

У Haskell значення immutable за замовчуванням.

Приклад:

x = 10

Це не змінна у звичному імперативному сенсі. Це binding імені x до значення 10.

Immutability допомагає:

  • уникати випадкової зміни стану;
  • спрощувати reasoning;
  • краще працювати з concurrency;
  • зменшувати кількість bugs.

Lazy evaluation

Lazy evaluation означає, що вирази обчислюються не одразу, а коли результат справді потрібен.

Приклад:

take 5 [1..]

У Haskell це працює: нескінченний список [1..] не обчислюється повністю. Беруться лише перші 5 елементів.

Цікаво: lazy evaluation дозволяє працювати з потенційно нескінченними структурами. Але вона також може створювати performance surprises, якщо не розуміти, коли саме обчислюються значення.

Strictness

Strictness — протилежний підхід до lazy evaluation: значення обчислюється раніше.

У Haskell іноді потрібно явно керувати strictness, щоб уникнути:

  • memory leaks;
  • накопичення thunks;
  • неочікуваного використання пам’яті;
  • performance problems.

Для цього використовують:

  • bang patterns;
  • seq;
  • strict data fields;
  • strict libraries;
  • profiling.

Thunk

Thunk — відкладене обчислення.

Через lazy evaluation Haskell може створювати thunks замість негайного обчислення значень.

Це корисно для laziness, але якщо thunks накопичуються, може зрости використання пам’яті.

Типи

Haskell має сильну статичну типізацію.

Приклад:

name :: String
name = "Haskell"

count :: Int
count = 10

Типи допомагають:

  • ловити помилки під час компіляції;
  • документувати наміри;
  • моделювати domain;
  • забороняти неможливі стани;
  • робити refactoring безпечнішим.

Type inference

Haskell має потужний type inference.

Можна написати:

double x = x * 2

GHC сам виведе тип.

Але в production-коді часто корисно писати type signatures:

double :: Num a => a -> a
double x = x * 2

Type signatures документують код і допомагають ловити помилки раніше.

Algebraic Data Types

Algebraic Data Types або ADT — один із найсильніших інструментів Haskell.

Приклад:

data OrderStatus
  = Draft
  | Paid
  | Cancelled

Це означає: статус замовлення може бути тільки Draft, Paid або Cancelled.

ADT допомагають явно описувати domain states.

Product types і sum types

Product type містить кілька полів.

Приклад:

data Customer = Customer
  { customerId :: Int
  , customerName :: String
  }

Sum type описує вибір між варіантами.

Приклад:

data PaymentResult
  = PaymentOk
  | PaymentDeclined String
  | PaymentError String

Sum types дозволяють моделювати бізнес-логіку без неявних null або magic strings.

Pattern matching

Pattern matching — спосіб розібрати значення за формою.

Приклад:

statusText :: OrderStatus -> String
statusText Draft = "Чернетка"
statusText Paid = "Оплачено"
statusText Cancelled = "Скасовано"

Pattern matching робить код дуже читабельним для обробки ADT.

Guards

Guards дозволяють писати умовну логіку.

Приклад:

discount :: Int -> Int
discount amount
  | amount > 10000 = 20
  | amount > 5000  = 10
  | otherwise      = 0

Guards часто роблять код чистішим, ніж nested if.

Maybe

Maybe — тип для значення, яке може бути відсутнім.

Приклад:

data Maybe a = Nothing | Just a

Практичне використання:

findCustomer :: Int -> Maybe Customer

Це означає: customer може бути знайдений або ні.

Практична користь: замість null Haskell використовує тип Maybe. Компілятор змушує вас обробити випадок, коли значення немає.

Either

Either часто використовується для результату з помилкою.

Приклад:

parseAmount :: String -> Either String Int

Це означає:

  • Right Int — успішний результат;
  • Left String — помилка.

Either корисний для validation, parsing, API responses і business rules.

Type classes

Type class — механізм ad-hoc polymorphism.

Приклад:

class Printable a where
  printValue :: a -> String

Тип може мати instance:

instance Printable Customer where
  printValue customer = customerName customer

Type classes схожі на interfaces, але мають іншу семантику й велику роль у Haskell ecosystem.

Eq, Ord, Show, Read

Базові type classes:

  • Eq — порівняння на рівність;
  • Ord — порядок;
  • Show — перетворення в рядок;
  • Read — читання з рядка.

Приклад:

data Status = Draft | Paid
  deriving (Eq, Show)

deriving автоматично створює instances.

Functor

Functor — type class для контейнерів або контекстів, над якими можна застосувати функцію.

Ключова функція:

fmap :: Functor f => (a -> b) -> f a -> f b

Приклад:

fmap (+1) (Just 10)
-- Just 11

Functor дозволяє працювати з “значенням у контексті”, не витягуючи його вручну.

Applicative

Applicative — abstraction між Functor і Monad.

Вона дозволяє застосовувати function у контексті до value у контексті.

Приклад ідеї:

pure (+) <*> Just 2 <*> Just 3
-- Just 5

Applicative часто використовують у validation, parsing і configuration.

Monad

Monad — abstraction для послідовного поєднання обчислень у контексті.

Ключова ідея: результат одного кроку впливає на наступний крок.

Приклад із Maybe:

findCustomer customerId >>= findPrimaryEmail

Якщо customer не знайдено, наступний крок не виконується.

Без містики: монада — це не “магія”. Це спосіб акуратно з’єднувати обчислення, які мають контекст: Maybe, Either, IO, список, state, parser тощо.

IO Monad

IO — тип для операцій, які взаємодіють із зовнішнім світом.

Приклад:

main :: IO ()
main = putStrLn "Hello, Haskell"

IO потрібен для:

  • читання файлів;
  • запису файлів;
  • network;
  • database;
  • console;
  • random;
  • time;
  • взаємодії з OS.

Haskell не забороняє side effects. Він робить їх явними у типах.

do notation

do notation — синтаксис для послідовних monadic operations.

Приклад:

main :: IO ()
main = do
  putStrLn "What is your name?"
  name <- getLine
  putStrLn ("Hello, " ++ name)

Це схоже на імперативний код, але типи все одно контролюють effects.

Higher-order functions

Haskell активно використовує functions як values.

Приклади:

map (*2) [1,2,3]
filter even [1..10]
foldr (+) 0 [1,2,3]

Higher-order functions дозволяють будувати дуже компактні transformations.

Function composition

Композиція функцій записується через ..

Приклад:

normalizeName :: String -> String
normalizeName = trim . toLower

Це означає: спочатку toLower, потім trim.

Function composition — один із ключових стилів Haskell-коду.

Currying

У Haskell функції технічно приймають один аргумент і можуть повертати функцію.

Приклад:

add :: Int -> Int -> Int
add a b = a + b

Це можна читати як:

Int -> (Int -> Int)

Тому можна частково застосовувати функції:

add10 = add 10
add10 5
-- 15

Recursion

У Haskell loops часто виражаються через recursion або higher-order functions.

Приклад:

sumList :: [Int] -> Int
sumList [] = 0
sumList (x:xs) = x + sumList xs

У production-коді часто використовують готові functions на кшталт sum, map, fold.

Lists

List — базова структура даних.

Приклад:

numbers :: [Int]
numbers = [1,2,3,4]

Операції:

head numbers
tail numbers
map (*2) numbers
filter even numbers