home.social

#ukrhaskell — Public Fediverse posts

Live and recent posts from across the Fediverse tagged #ukrhaskell, aggregated by home.social.

  1. CW: Кортежі у :haskell:

    Кортежі — це гетерогенні структури даних, фіксованої довжини, та з елементами здебільшого різних типів.

    Створюються вони за допомоги бінарного оператора (,).

    > (,) 'c' True
    ('c',True)
    

    При цьому в нас виходить двох елементний кортеж, часто його ще називають парою. Але кортежі можуть бути й довші, або коротші.

    Найкоротший кортеж - це порожній кортеж.

    > ()
    ()
    

    Якщо нам потрібно більше елементів, то значить треба додати більше ком. Але кортежу довжиною в один елемент не існує, оскільки синтаксично його не можливо створити через те що елемент в дужках, наприклад (3), це просто групування.

    > (,,) 4 'a' False
    (4,'a',False)
    > (,,,) 4 'a' False "Haskell"
    (4,'a',False,"Haskell")
    

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

    > (4, 'a', False, "Haskell")
    (4,'a',False,"Haskell")
    

    Тепер перейдемо до їхніх типів.

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

    Тип кортежів це ().

    > :t ()
    () :: ()
    

    Якщо це не порожній кортеж, то й тип не порожній.

    > :t ('c', True)
    ('c', True) :: (Char, Bool)
    

    Це все добре, але треба якось же із ними працювати й отримувати окремі елементи. У стандартній бібліотеці для цього є кілька готових функцій, наприклад візьмемо fst котра повертає перший елемент, та snd котра повертає другий елемент.

    > p = (1,2)
    > fst p
    1
    > snd p
    2
    

    Ці функції працюють тільки з парами, і реалізовуються через зіставлення.

    fst (x,_) = x
    snd (_,y) = y
    

    #ukrhaskell #haskell #tuple #кортежі #типи #програмування

  2. CW: Налаштування GHCI, інтерпритатора :haskell:

    Під час вивчання Haskell, та й, мабуть, під час роботи з ним, часто використовується інтерпретатор. На жаль, за замовчуванням він не дуже зручний, але частково ми можемо виправити це простими налаштуваннями.

    Всі налаштування робляться через його команду :set. До прикладу, часто може знадобитися переглядати типи функцій, чи їхніх значень після виконання. Робиться це командою :type передаючи певну конструкцію, але можна увімкнути автоматичний друк типів при виконанні кожної інструкції командою :set +t. Після цього виконання буде виглядати так:

    ghci> 4
    4
    it :: Num a => a
    ghci> 'N'
    'N'
    it :: Char
    ghci> 2 + 2 * 4
    10
    it :: Num a => a
    

    Тепер нам не потрібно виконувати окремі команди, щоб побачити значення та тип результату.

    Також можна змінити підказку (prompt) щоб не дивитись кожнісінький раз на те що ми й так знаємо, а саме що ми у ghci.

    ghci> :set prompt "> "
    > "It's a String"
    "It's a String"
    it :: String
    >
    

    Це вже краще, але далеко до ідеалу, тому додамо ще якусь корисну інформацію, окрім прибирання зайвої, наприклад номер рядка й завантажений модуль.

    > :set prompt "[%l] %s> "
    [7] Prelude>
    

    Так вже цікавіше.

    Є ще одна штучка котра може нам іноді знадобитись при тестах.

    [1] Prelude> f = do
    
    <interactive>:1:5: error: [GHC-82311]
        Empty 'do' block
        Suggested fix: Perhaps you intended to use NondecreasingIndentation
    [2] Prelude> :set +m
    [3] Prelude> f = do
    ghci|   putStrLn "Привіт всім хаскелятам та хаскелищам!"
    ghci|
    [6] Prelude> f
    Привіт всім хаскелятам та хаскелищам!
    [7] Prelude>
    

    :set +m дозволяє писати багато рядкові конструкції.

    Це все добре, але після перезапуску, всі налаштування загубляться у просторі всесвіту й ви втратите свої персональні налаштунки, а допомагає уникнути цього .ghci файл у домашній теці, або у поточній. Просто запишіть у нього всі необхідні команди й ви спаслись.

    #ukrhaskell #haskell #ghci #налаштування #prompt #set

  3. CW: Налаштування GHCI, інтерпритатора :haskell:

    Під час вивчання Haskell, та й, мабуть, під час роботи з ним, часто використовується інтерпретатор. На жаль, за замовчуванням він не дуже зручний, але частково ми можемо виправити це простими налаштуваннями.

    Всі налаштування робляться через його команду :set. До прикладу, часто може знадобитися переглядати типи функцій, чи їхніх значень після виконання. Робиться це командою :type передаючи певну конструкцію, але можна увімкнути автоматичний друк типів при виконанні кожної інструкції командою :set +t. Після цього виконання буде виглядати так:

    ghci> 4
    4
    it :: Num a => a
    ghci> 'N'
    'N'
    it :: Char
    ghci> 2 + 2 * 4
    10
    it :: Num a => a
    

    Тепер нам не потрібно виконувати окремі команди, щоб побачити значення та тип результату.

    Також можна змінити підказку (prompt) щоб не дивитись кожнісінький раз на те що ми й так знаємо, а саме що ми у ghci.

    ghci> :set prompt "> "
    > "It's a String"
    "It's a String"
    it :: String
    >
    

    Це вже краще, але далеко до ідеалу, тому додамо ще якусь корисну інформацію, окрім прибирання зайвої, наприклад номер рядка й завантажений модуль.

    > :set prompt "[%l] %s> "
    [7] Prelude>
    

    Так вже цікавіше.

    Є ще одна штучка котра може нам іноді знадобитись при тестах.

    [1] Prelude> f = do
    
    <interactive>:1:5: error: [GHC-82311]
        Empty 'do' block
        Suggested fix: Perhaps you intended to use NondecreasingIndentation
    [2] Prelude> :set +m
    [3] Prelude> f = do
    ghci|   putStrLn "Привіт всім хаскелятам та хаскелищам!"
    ghci|
    [6] Prelude> f
    Привіт всім хаскелятам та хаскелищам!
    [7] Prelude>
    

    :set +m дозволяє писати багато рядкові конструкції.

    Це все добре, але після перезапуску, всі налаштування загубляться у просторі всесвіту й ви втратите свої персональні налаштунки, а допомагає уникнути цього .ghci файл у домашній теці, або у поточній. Просто запишіть у нього всі необхідні команди й ви спаслись.

    #ukrhaskell #haskell #ghci #налаштування #prompt #set

  4. CW: Налаштування GHCI, інтерпритатора :haskell:

    Під час вивчання Haskell, та й, мабуть, під час роботи з ним, часто використовується інтерпретатор. На жаль, за замовчуванням він не дуже зручний, але частково ми можемо виправити це простими налаштуваннями.

    Всі налаштування робляться через його команду :set. До прикладу, часто може знадобитися переглядати типи функцій, чи їхніх значень після виконання. Робиться це командою :type передаючи певну конструкцію, але можна увімкнути автоматичний друк типів при виконанні кожної інструкції командою :set +t. Після цього виконання буде виглядати так:

    ghci> 4
    4
    it :: Num a => a
    ghci> 'N'
    'N'
    it :: Char
    ghci> 2 + 2 * 4
    10
    it :: Num a => a
    

    Тепер нам не потрібно виконувати окремі команди, щоб побачити значення та тип результату.

    Також можна змінити підказку (prompt) щоб не дивитись кожнісінький раз на те що ми й так знаємо, а саме що ми у ghci.

    ghci> :set prompt "> "
    > "It's a String"
    "It's a String"
    it :: String
    >
    

    Це вже краще, але далеко до ідеалу, тому додамо ще якусь корисну інформацію, окрім прибирання зайвої, наприклад номер рядка й завантажений модуль.

    > :set prompt "[%l] %s> "
    [7] Prelude>
    

    Так вже цікавіше.

    Є ще одна штучка котра може нам іноді знадобитись при тестах.

    [1] Prelude> f = do
    
    <interactive>:1:5: error: [GHC-82311]
        Empty 'do' block
        Suggested fix: Perhaps you intended to use NondecreasingIndentation
    [2] Prelude> :set +m
    [3] Prelude> f = do
    ghci|   putStrLn "Привіт всім хаскелятам та хаскелищам!"
    ghci|
    [6] Prelude> f
    Привіт всім хаскелятам та хаскелищам!
    [7] Prelude>
    

    :set +m дозволяє писати багато рядкові конструкції.

    Це все добре, але після перезапуску, всі налаштування загубляться у просторі всесвіту й ви втратите свої персональні налаштунки, а допомагає уникнути цього .ghci файл у домашній теці, або у поточній. Просто запишіть у нього всі необхідні команди й ви спаслись.

    #ukrhaskell #haskell #ghci #налаштування #prompt #set

  5. CW: :haskell: функції error та undefined

    error та undefined це не звичайні функції. Крім того, що вони поліморфні, та ще й переривають виконання.

    Перша приймає рядок з повідомленням помилки й виводить його на екран, а друга просто перериває обчислення.

    Їхній поліморфізм полягає в типі повернення, й потрібен для того, щоб можна було їх викликати будь-де.

    λ> error "Упс, щось не так."
    *** Exception: Упс, щось не так.
    CallStack (from HasCallStack):
      error, called at <interactive>:4:1 in interactive:Ghci1
    λ> undefined
    *** Exception: Prelude.undefined
    CallStack (from HasCallStack):
      undefined, called at <interactive>:5:1 in interactive:Ghci1
    

    #ukrhaskell #haskell #error #undefined #поліморфізм #програмування

  6. CW: :haskell:, конструкція where

    Окрім виразу let in є ще схожа конструкція where. Вона виконує ту ж функцію, але трохи по інакшому.

    g n = x+2*x where x = n^3+2
    

    На перший погляд, змінилась тільки послідовність оголошення та використання функцій, і це майже правильно. Ключова відмінність у, тому що let in це вираз, а where конструкція. Тому друге можна використовувати там де не можна перше, наприклад при використанні кількох визначень з охоронними виразами чи зіставленнями.

    f x | x > 0 = y * 2
        | x < 0 = y / 2
      where y = cos x^2
    

    На жаль приклад дуже не дуже, але є що є.

    Тут оголошені функції після whare можна використовувати в усіх визначеннях f, й навіть в охоронних виразах. let in такого не дозволяє.

    #ukrhaskell #haskell #where #letin #вираз #конструкція #підфункції #охоронні_вирази #програмування

  7. CW: Відступи в синтаксисі :haskell:

    У синтаксисі Haskell як і у Python відступи грають важливу роль. Коли у нас є довге визначення і ми хочемо розбити його на менші й зрозуміліші частини потрібно якось уточнити що це не нове оголошення, а продовження попереднього.

    Для прикладу візьмемо вираз if then else, бо інші ми ще не вивчали.

    f x = if x > 0 then True else False
    

    У цьому виразі немає великих значень чи формул, але ми розглянемо його для простого розуміння. Розбити його на окремі рядки ми можемо так.

    f x =
      if x > 0
      then True
      else False
    

    Або так.

    f x =
      if x > 0 then
        True
      else
        False
    

    Кількість пробілів не має значення. Головне що їх було, або таж кількість, або більше. Якщо відступ відсутній, то це означає що починається нове оголошення.

    !! Один символ табуляції завжди вважається як 8 пробілів.

    #ukrhaskell #програмування #haskell #відсупи #табуляція #синтаксис #syntax #spaces #tab

  8. CW: Швидкий запуск програми на :haskell:

    Під час розробки часто потрібно перезапускати програму перевіряючи її поведінку. Але робити це за допомоги інтерпретатора ghci запускаючи функцію не завжди зручно, та й збирати компілятором ghc і запускати бінарник також. Тому для зручності було зроблено runghc. Це команда яка компілює код і зразу його виконує не зберігаючи у файл.

    $ runghc main.hs
    

    #ukrhaskell #haskell #ghc #ghci #runghc #запуск #програмування

  9. CW: Швидкий запуск програми на :haskell:

    Під час розробки часто потрібно перезапускати програму перевіряючи її поведінку. Але робити це за допомоги інтерпретатора ghci запускаючи функцію не завжди зручно, та й збирати компілятором ghc і запускати бінарник також. Тому для зручності було зроблено runghc. Це команда яка компілює код і зразу його виконує не зберігаючи у файл.

    $ runghc main.hs
    

    #ukrhaskell #haskell #ghc #ghci #runghc #запуск #програмування

  10. CW: Оператор $ у :haskell:

    Через те що у Haskell аргументи функції не вкладаються у дужки при спробі передати результат однієї функції в іншу потрібно використати дужки для групування.

    foo bar x    -- Функції передаються два аргументи bar і x
    foo (bar x)  -- Функції bar передається аргумент x і її результат підставиться як один аргумент функції foo
    

    У цьому простому прикладі все виглядає просто і зрозуміло, але якщо у нас був би складніший вираз з іншими дужками все виглядало б не так зрозуміло.

    Для полегшення додали спеціальний оператор зниження пріоритету. Складається він з одного символу $. Використати його ми можемо тут підставивши між функціями.

    foo $ bar x
    

    Результат буде той же що й з дужками.

    Цей оператор має праву асоціативність і найнижчий пріоритет. Перевірити це ми можемо в інтерпретаторі.

    > :i ($)
    ($) :: (a -> b) -> a -> b 	-- Defined in ‘GHC.Base’
    infixr 0 $
    

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

    ($) f x = f x
    

    #ukrhaskell #програмування #haskell #оператор #$ #пріоритет #функції