Блоґ одного кібера

Історія хвороби контуженого інформаційним вибухом

В функціональному стилі дужок забагато не буває

with 11 comments

Показую. Нехай в нас є клас, в якого є атрибути a та b, а b має ще атрибут с. І нам треба отримати хоч щось з двох, якщо їм присвоєне якесь нехибне в булевому контексті значення. Якось так:

class Stuff(object):
    @property
    def any(self):
        return (
            self.a or
            self.b.c if self.b else 'Doh!'
        )
stuff = Stuff()
stuff.a = True
stuff.b = None

print stuff.any


Виводить 'Doh!'.

Бо тернарний оператор має менший пріоритет ніж or!. Що звичайно при такому форматуванні коду абсолютно непомітно, крім того якось звично що диз’юнкція має найменший пріоритет в логіці.

Краще напевне писати імперативніше:

class Stuff2(object):
    @property
    def any(self):
        a = self.a
        b = self.b.c if self.b else 'Doh!'
        return a or b
stuff = Stuff2()
stuff.a = True
stuff.b = None

print stuff.any

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

P.S. Ніяк не розумію, як люди можуть обходитись без змінних… Навіть в математиці, де все описують дуже функціональними значками суми, інтегралу та кванторами люблять написати: Неай \sqrt{x} = t

Всі персонажі цієї нотатки вигадані. Будь-яка схожість з реальними ідентифікаторами випадкова.

Advertisements

Written by bunyk

Грудень 2, 2011 at 20:33

Оприлюднено в Кодерство

Tagged with ,

Відповідей: 11

Subscribe to comments with RSS.

  1. Дійсно, в Пітоні уникати змінних було б дуже дивно. Мій крихітний досвід функціонального програмування показує, що не в цьому суть)
    А щодо змінних, то тим більше мене дивує те, що навіть ті нечасті вживання «ідентифікаторів» у Хаскелі — це часто позначення змінних практично в математичному сенсі.

    dmytrish

    Грудень 2, 2011 at 20:56

    • Ах, точно, я забув, що в функціональному програмуванні якщо y = sin(x), то він дорівнює і не змінюється, як в математиці. Якщо звісно не y(t) і не x(t). Чувак юзающий регекспы мені про це вже раз казав.

      bunyk

      Грудень 2, 2011 at 21:12

      • Суть навіть не так у цьому, а в тому, що ідентифікатори позначають абстрактніші сутності: прив’язка ідентифікатора до реального місця в пам’яті розмивається (наприклад, компілятор може поводитись із нею дуже вільно, може симулювати його присутність, може обчислювати його на місці і так далі) настільки, що він ніби стає математичним позначенням (але для цього мова має бути функціонально чиста). Будь-яке оголошення ж змінної як конкретної ділянки пам’яті із власною індивідуальністю сильно обмежує функціональний підхід, хоч деякі його елементи бувають корисними і в звичайних мовах (map, iterate, for in, генератори).

        Офтоп: я прочитав половинку розумної книжки і мене вставило 🙂

        Dmytro Sirenko

        Грудень 3, 2011 at 11:03

        • Я половину SICP-а прочитав. Теж вставило. Тепер совість мучить що лиш половину. 🙂

          bunyk

          Грудень 3, 2011 at 15:16

  2. Петонопроблеми.
    Взагалі заголовок правильний, тільки потрібно забрати перші три слова. Хтось недавно хвалився в треді на G+, що Петон – дуже експлісітна мова. Так навіщо залишати такі рудиментарні речі, як імплісітний order of evaluation? Економія на сірниках?
    Ну і п’ятихвилинка ліспів:

    => (defn foo [arg] 
           (or (:a arg) 
                 (:c (:b arg)) 
                 "Doh!"))
    => (foo {:a nil :b 3})
    "Doh!"
    => (foo {:a nil :b {:c 3}})
    3
    => (foo {:a 1 :b {:c 3}})
    1
    

    Щодо змінних^Wлексичних біндінгів – ніхто не старається без них обійтись. Тільки це ні разу не змінні.

    alexyakushev

    Грудень 3, 2011 at 10:28

    • \troll{
      Неявний порядок обчислень тому, що люди пишуть 2+3*4, і мають на увазі саме 14 а не 20. А ваші Ліспи створені бути зрозумілішими для комп’ютера, який любить аби йому вказували все, аж до порядку операцій, тому ви й записуєте синтаксичне дерево явно, чого навіть калькулятор мого брата не вимагає.
      }

      Є ще проблема в тому, що через жорстоку реальність більшість програмного забезпечення написана мовами які не є ідеальними, і Python – не найгірша з них. І взагалі все програмне забезпечення – жахливе legacy, яке крім того криво написано.

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

      Напевне в тетріс: http://codethat.wordpress.com/2011/09/10/writing-tetris-in-clojure/
      Або малювати картинки: http://nakkaya.com/2010/04/20/fractals-in-clojure-newton-fractal/

      bunyk

      Грудень 3, 2011 at 15:11

      • 2+3*4 ти припустим можеш просто без дужок читати, а вот з першого погляду вираз на 10 аргументів вже не розбереш. Кажеш, розставиш там пару дужок де потрібно? 3 замість 5-ох? Та сама економія на сірниках.
        >> Неявний порядок обчислень тому, що люди пишуть… А ваші Ліспи створені бути зрозумілішими для комп’ютера…
        В тебе топік про що? Про те, що порядок виконання в Петоні в деяких місцях не зрозумілий і несподіваний для людини. Так чого ти заливаєш, що він створений для людей?
        >> вирішив що діалектом Ліспа який я вивчу буде Clojure
        А ось це правильно. Тільки по-перше, щоб ефективно використовувати Clojure треба більш-менш розбиратись в Джавівській екосистемі, по-друге, замість гратись візьми краще якусь фундаментальну книжку. Joy of Clojure менінговський саме воно.

        alexyakushev

        Грудень 4, 2011 at 21:27

  3. хороша спроба наїхати на функціональщиків. Єдина проблема, що обидва твої варіанти написано, якщо можна так виразитись, у функціональному стилі.

    Чому другий варіант також? Порівняй наступний ML текст зі своїм:

        member any() =
            let a = self.a in
            let b = if self.b then self.b.c else 'Doh!' in
            a or b
    

    Якщо ми пишемо на F#, то навіть слово in писати не потрібно, оскільки в ньому блоки відділяються індентами (як і в пайтоні).

    Твій стиль був функціональним, бо ти не використовував змінний стан, ти просто створив аліаси для значень (або обчислень), що є зрозумілим ходом для забезпечення читабельності коду.

    (єдина проблема – ML статичний до мозку кісток, тому цей код може взагалі не знадобитись)

    danbstt

    Грудень 3, 2011 at 16:41

    • Та хто там на вас функціональщиків наїжджає. Я хотів написати

              return (
                  self.a or
                  (self.b.c if self.b else 'Doh!')
              )
      

      Але потім подумав що якщо я записав то в змінні аби легше було дебажити друкуючи їх, то краще так і залишити, бо
      1. Це еквівалентно тим же дужкам.
      2. Це буде легше дебажити.

      Ну, і звісно, там не було ніякого змінного стану.

      bunyk

      Грудень 8, 2011 at 22:21

  4. Он ezyang пише, що хаскелісти не люблять зайві дужки та зайві імена.

    http://blog.ezyang.com/2011/11/how-to-read-haskell/

    І в цьому він has a point.

    ulidtko

    Грудень 8, 2011 at 11:33

    • Я теж думаю що хаскелісти – дивні люди.

      P.S. Щось я по тій статті читати хаскель не навчився. 😦

      bunyk

      Грудень 8, 2011 at 22:17


Залишити відповідь

Заповніть поля нижче або авторизуйтесь клікнувши по іконці

Лого WordPress.com

Ви коментуєте, використовуючи свій обліковий запис WordPress.com. Log Out / Змінити )

Twitter picture

Ви коментуєте, використовуючи свій обліковий запис Twitter. Log Out / Змінити )

Facebook photo

Ви коментуєте, використовуючи свій обліковий запис Facebook. Log Out / Змінити )

Google+ photo

Ви коментуєте, використовуючи свій обліковий запис Google+. Log Out / Змінити )

З’єднання з %s

%d блогерам подобається це: