неділя, 21 грудня 2008 р.

Мова програмування Scheme

Яку мову обрати для навчання програмуванню? Взагалі тема звичайно холіварна. Можливо я якось викладу свої думки у окремій статті, бо думок дійсно багато. Але я впевнений у тому, що вивчення програмування ні в якому разі, не варто починати десь з середини (і однозначно не з PHP). Спочатку потрібно натренувати мозок, вміння створювати алгоритми і описувати їх знаючи можливості тієї чи іншої мови. У вітчизняних школах та вузах зазвичай вивчають програмування на прикладі Basic чи Pascal. Я сам дуже поважаю Pascal і досі вважаю його однією з найкращих мов для навчання, це строга мова зі статичною типізацією, яка дозволяє без зайвих проблем відпрацювати принципи процедурного та об'єктно-орієнтованого програмування. Але, познайомившись з навчальними матеріалами провідних західних університетів (Berkeley, Stanford, MIT), а також базуючись на власному досвіді самоосвіти, сходжуся на думці, що непогано було б почати вивчення з однієї з функціональних мов. У плані тренування мозку імхо штука ідеальна. Взагалі, досить дивно, але функціональна парадигма вперто ігнорується вітчизняною освітою. Щоб якось згладити цей пробіл, я хотів би розповісти про мову програмування Scheme (читається "скіім"). Це один з найпопулярніших діалектів Lisp - однієї з найстаріших (разом з Fortran) мов програмування, яка досі широко використовується і якій нещодавно виповнилося 50 років. Scheme викладається в Berkeley (курс CS61A) та MIT у якості першої мови програмування, його інтерпретатор інтегровано в GIMP де він має назву Script-Fu. Scheme також використовується в Dia. Різноманітні діалекти Lisp також використовуються в Emacs, AutoCAD та ін. програмах.

Scheme - це дуже проста мова програмування. Її цілком можна вивчити за один день, але ця простота оманлива. Scheme одночасно і дуже потужна мова. Існує величезна кількість реалізацій, я використовую Guile. Встановити інтерпретатор дуже просто:
sudo apt-get install guile

Програми можна або зберігати у *.scm файлах, або можна використовувати інтерактивний режим інтерпретатору, по аналогії з Python.

Константи та змінні

Отже, приступимо до вивчення основних структур Scheme. Перш за все, визначимося з константами:
123 - ціле число
3.1415926 - дробове число
2+3i - комплексне число
2/3 - дріб
#b1111 - двійкове число
#xFF - шістнадцяткове стаття
#o123 - вісімкове число
#\A - одиничний символ
"Hello, World!" - символьний рядок
'hello - символ
#f - логіче значення

З константами можна здійснювати операції з допомогою операторів або функцій. Врешті решт Scheme є функціональною мовою, а тому у ній все є функцією. З математики ви знайомі з формою запису функцій f(x) або t(a,b). Але те ж саме можна записати і у вигляді (f x) чи (t a b). Саме таку форму запису використовує Scheme. З погляду на це, і арифметичні вирази записуються не у звичній багатьом інфіксній формі, як наприклад 2+3, а у префіксній - (+ 2 3). Наприклад:
guile> (* 2 5)
10
guile> (+ (* 3 4) (/ 5 2))
29/2
guile> (+ 1 1 1 1 1)
5
guile> (/ 2)
1/2
guile> (expt 2 3) - степінь
8
guile> (sqrt 2)
1.4142135623731

Для оголошення змінних використовується конструкція (define ім'я значення)
guile> (define a 2)
guile> (define b 2)
guile> (+ a b)
4

Значення вже існуючої змінної можна змінити з допомогою конструкції (set! ім'я значення)
guile> (set! a 5)
guile> a
5


Функції

Функції оголошуються з допомогою конструкції (define (ім'я параметри) тіло_функції)
guile> (define (square x) (* x x))
guile> (square 3)
9

Для демонстрації рекурсії наведу приклад обчислення факторіалу:
(define (fact x)
(if (= x 1)
1
(* x (fact (- x 1)))))

Як ви вже зрозуміли, перевірку умови можна виконувати з допомогою конструкції (if умова якщо_так якщо_ні)

Введення/виведення

Не заглиблюючись у подробиці, зверну увагу на основні функції
(display "Hello, World!") - вивести рядок
(newline) - перейти на новий рядок
(read) - прочитати ввід з клавіатури


Списки

Для роботи з наборами даних зручно використовувати списки
guile> (define nums (list 1 2 3 4 5 6 7 8 9 10)) - оголошуємо список
guile> (list-ref nums 0) - читаємо елемент з номером 0
1
guile> (car nums) - читаємо перший елемент
1
guile> (cdr nums) - читаємо всі інші елементи
(2 3 4 5 6 7 8 9 10)

Можна також обробити всі елементи списку одним заходом
згенерувати новий список застосувавши функцію для кожного елемента
guile> (map square nums)
(1 4 9 16 25 36 49 64 81 100)
guile> (map (lambda (x) (* x 3)) nums)
(3 6 9 12 15 18 21 24 27 30)

Конструкція lambda дозволяє оголошувати функції по мірі потреби, не даючи їм імен. Якщо ви програмуєте на Python'і, то вже знаєте ці конструкції, саме з Lisp'у вони й були запозичені.

Цикли

Насправді, Scheme не має циклів у тому вигляді як вони є в імперативних мовах. Тут для тих же цілей використовується рекурсія. Наприклад, виведемо у стовпчик вміст списку
(define (print-list lst)
(if (not (null? lst))
(begin (display (car lst))
(newline)
(print-list (cdr lst)))))

Конструкція (begin ...) використовується у тому випадку, якщо потрібно вставити декілька операторів там де по синтаксису допускається лише один.

Наступна конструкція дозволяє змоделювати відомий по іншим мовам програмування цикл for:
(let loop ((i 1))
(display i)
(newline)
(if (<= i 10) (loop (+ i 1))))

Конструкція let використовується у тому випадку коли в рамках виразу потрібно оголосити локальні змінні, або якщо потрібно оголосити вкладену функцію. Таким чином можна реалізовувати практично всі можливі варіанти циклів. Звичайно, завжди можна створити власну функцію для скорочення форми запису, адже функції можна передавати у вигляді параметрів інших функцій, так як і прості дані. Взагалі, Scheme дозволяє підігнати мову під себе так як подобається. Вражаюче гнучка мова.

Для прикладу, можна навести реалізацію функції обчислення визначеного інтегралу
(define (func x)
x)

(define (integrate a b e f)
(define sum 0)
(let loop ((i a))
(if (< i b) (begin
(set! sum (+ sum (* (f i) e)))
(loop (+ i e)))))
sum)

(display (integrate 0 1 0.01 func))
(newline)


Звичайно, можна було б продовжувати далі, але це зайняло б дуже багато місця. Основні ж конструкції ми розглянули. Якщо ви зацікавились Scheme, то додаткову інформацію завжди зможете знайти за наступними адресами:
Офіційний сайт Guile
Введение в язык Scheme для школьников
Сторінка про Scheme на сайті MIT
Schemers.org
Відеозаписи лекцій по курсу The Structure and Interpretation of Computer Programs в університеті Berkeley

Взагалі, оскільки Scheme - мова академічна, то інформації по ній досить багато. У той же час, знання даної мови дозволить не лише по новому глянути на різноманітні конструкції в інших мовах (як Python наприклад). Той же Guile, легко інтегрується в програми на C, що дозволяє виносити код назовні.

3 коментарі:

  1. Для навчання програмування у школі - однозначно Python або Ruby. Щоб не забивати дітям дурним голову.
    А для вузу підійде будь-яка мова. Всі вони по-своєму корисні для для тренування мозку. :)

    ВідповістиВидалити
  2. Ще дещо про мови. :)
    http://www.aegisub.net/2008/12/if-programming-languages-were-religions.html

    ВідповістиВидалити
  3. Щодо школи, згоден. Python - ідеальний вибір. Тут же я мав на увазі підготовку програміста у технічному вузі. Це вже повинен бути інший рівень.

    А креатив про мови сподобався.

    ВідповістиВидалити