home.social

#типи — Public Fediverse posts

Live and recent posts from across the Fediverse tagged #типи, 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. Як же мене після C++ навіть на Python тягне оптимізувати там де ніхто не звертає уваги. До прикладу багато хто використовує всюди списки дам де це не потрібно і можна взяти кортеж.

    Обʼєкт типу object займає 16 BYTES. Це можна дізнатись викликавши метод __sizeof__ в обʼєкта.

    o = object()
    o.__sizeof__()
    

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

    >>> issubclass(int, object)
    True
    >>> issubclass(float, object)
    True
    >>> issubclass(bool, object)
    True
    >>> issubclass(str, object)
    True
    >>> issubclass(list, object)
    True
    >>> issubclass(tuple, object)
    True
    >>> class A:
    ...     pass
    ... 
    >>> issubclass(A, object)
    True
    

    Саме через це всі обʼєкти мають функцію __sizeof__ і не тільки.

    Якщо ми подивимось на розміри стандартних типів, то можемо трохи здивуватись.

    >>> int().__sizeof__()
    28
    >>> float().__sizeof__()
    24
    >>> bool().__sizeof__()
    28
    >>> str().__sizeof__()
    49
    >>> tuple().__sizeof__()
    24
    >>> list().__sizeof__()
    40
    >>> set().__sizeof__()
    200
    >>> dict().__sizeof__()
    48
    

    Найбільше я здивувався розміру типу bool. Він займає скільки ж як і int, і є більшим за float та tuple. І це все розміри порожніх (нульових) обʼєктів.

    Тепер порівняємо кортежі та списками з однаковим вмістом.

    >>> t = (1,2,3,4,5,6)
    >>> l = [1,2,3,4,5,6]
    
    >>> t.__sizeof__()
    72
    >>> l.__sizeof__()
    88
    

    Різниця та ж що й при порожніх контейнерах через те що контейнер зберігає тільки посилання на обʼєкт. Можемо в цьому переконатись за id обʼєктів.

    >>> id(t[0]) == id(l[0])
    True
    >>> t[0] is l[0]
    True
    

    Оператор is робить те саме, він порівнює ідентифікатори.

    Це добре що python оптимізує програму не створюючи зайвих обʼєктів, але всеодно всі обʼєкти займають дуже багато місця. Саме через це я й ненавиджу такі мови як python, js...

    #програмування #python #sizeof #розміри #типи #int #float #list #tuple #списки #кортежі #sizeof #object #оптимізація #бісить

  3. CW: Типи в :haskell:

    Haskell є строго статично типізованою мовою програмування, але з можливістю автоматичного виведення типів. В усіх наших попередніх програмах ми ніде не вказували типи, компілятор чи інтерпретатор їх вивів автоматично, полегшивши нам написання коду. Але не завжди це у нього буде вдаватись, і взагалі знати типи даних обовʼязково потрібно.

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

    Щоб дізнатись тип функції чи оператора в інтерпретаторі ghci потрібно використати команду інтерпретатора type. Всі команди інтерпретатора починаються з символу двокрапки. Виглядає це так :type x.

    let x = 10
    :type x
    

    Команди інтерпретатора можна скорочувати до першої літери, але тільки якщо не відбувається колізії. Тому :type і :t одне і теж.

    Ця команда поверне нам

    x :: Num p => p
    

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

    let x = 10 :: Int
    

    Тут ми явно вказуємо тип за допомоги оператора типізації. Тепер команда типу :t x поверне нам таке x :: Int.

    Є шість основних, фундаментальних типів.

    • Bool - Логічний (True, False)
    • Char - Символьний ('\0' - '\1114111')
    • Int - Знаковий цілочисельний (-9223372036854775808 - 9223372036854775807)
    • Integer - Знаковий цілочисельний без обмежень)
    • Float - Знаковий дробовий
    • Double - Знаковий дробовий з подвійною точністю

    Перейдімо від констант до функцій. Для прикладу візьмемо стандартну функцію not. Вона приймає bool і повертає інвертоване значення типу bool.

    not True  -- Поверне False
    not False -- Поверне True
    

    Тепер розберемо його тип

    :t not
    not :: Bool -> Bool
    

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

    Для прикладу візьмемо оператор &&. Щоб подивитись тип оператора потрібно взяти його у душки :t (&&).

    (&&) :: Bool -> Bool -> Bool
    

    Перші два Bool це вхідні аргументи, а останній тип повернення. Саме через такі типи працює часткове застосування функцій. Візьмем (&& True) і побачимо що тип його (&& True) :: Bool -> Bool. Розташування аргументу значення не має.

    #програмування #haskell #типи #типізація #статична #строга #фукції #оператори #інтерпретатор #ghci #команди #type #types #typing #static #константи

  4. CW: Типи в :haskell:

    Haskell є строго статично типізованою мовою програмування, але з можливістю автоматичного виведення типів. В усіх наших попередніх програмах ми ніде не вказували типи, компілятор чи інтерпретатор їх вивів автоматично, полегшивши нам написання коду. Але не завжди це у нього буде вдаватись, і взагалі знати типи даних обовʼязково потрібно.

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

    Щоб дізнатись тип функції чи оператора в інтерпретаторі ghci потрібно використати команду інтерпретатора type. Всі команди інтерпретатора починаються з символу двокрапки. Виглядає це так :type x.

    let x = 10
    :type x
    

    Команди інтерпретатора можна скорочувати до першої літери, але тільки якщо не відбувається колізії. Тому :type і :t одне і теж.

    Ця команда поверне нам

    x :: Num p => p
    

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

    let x = 10 :: Int
    

    Тут ми явно вказуємо тип за допомоги оператора типізації. Тепер команда типу :t x поверне нам таке x :: Int.

    Є шість основних, фундаментальних типів.

    • Bool - Логічний (True, False)
    • Char - Символьний ('\0' - '\1114111')
    • Int - Знаковий цілочисельний (-9223372036854775808 - 9223372036854775807)
    • Integer - Знаковий цілочисельний без обмежень)
    • Float - Знаковий дробовий
    • Double - Знаковий дробовий з подвійною точністю

    Перейдімо від констант до функцій. Для прикладу візьмемо стандартну функцію not. Вона приймає bool і повертає інвертоване значення типу bool.

    not True  -- Поверне False
    not False -- Поверне True
    

    Тепер розберемо його тип

    :t not
    not :: Bool -> Bool
    

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

    Для прикладу візьмемо оператор &&. Щоб подивитись тип оператора потрібно взяти його у душки :t (&&).

    (&&) :: Bool -> Bool -> Bool
    

    Перші два Bool це вхідні аргументи, а останній тип повернення. Саме через такі типи працює часткове застосування функцій. Візьмем (&& True) і побачимо що тип його (&& True) :: Bool -> Bool. Розташування аргументу значення не має.

    #програмування #haskell #типи #типізація #статична #строга #фукції #оператори #інтерпретатор #ghci #команди #type #types #typing #static #константи