яке призначення стрілок?


62

Я вивчаю функціональне програмування з Haskell, і намагаюся схопити поняття, спочатку зрозумівши, для чого вони мені потрібні.

Я хотів би знати мету стрілок у функціональних мовах програмування. Яку проблему вони вирішують? Я перевірив http://en.wikibooks.org/wiki/Haskell/Understanding_arrows та http://www.cse.chalmers.se/~rjmh/afp-arrows.pdf . Все, що я розумію, - це те, що вони використовуються для опису графіків для обчислень, і що вони дозволяють простіше кодувати вільне стильне кодування.

У статті передбачається, що стильний вільний стиль, як правило, простіше зрозуміти та написати. Це здається мені досить суб’єктивно. В іншій статті ( http://en.wikibooks.org/wiki/Haskell/StephensArrowTutorial#Hangman:_Main_program ) реалізована гра з вішанкою, але я не бачу, як стрілки роблять цю реалізацію природною.

Я міг знайти багато паперів, що описують концепцію, але нічого про мотивацію.

Що мені не вистачає?

Відповіді:


42

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

По-перше, ви можете продуктивно вирішити більшість проблем у Haskell, не тягнучись до стрілок. Деякі помітні Haskellers справді не люблять і не користуються ними (див. Тут , тут і тут докладніше про це). Тож якщо ви говорите собі "Ей, мені це не потрібно", розумійте, що ви справді можете бути правильними.

Що мене найбільше засмутило у Стрілок, коли я вперше дізнався їх, - це те, як підручники з цього питання неминуче досягали аналогії схеми. Якщо ви подивитесь на код стрілки - принаймні, сортований сорт - він не нагадує ні що так багато, як Hardware Definding Language. Ваші входи розташовуються праворуч, ваші виходи ліворуч, і якщо ви не вдається провести їх належним чином, вони просто не спрацюють. Я подумав собі: справді? Тут ми закінчилися? Чи ми створили мову настільки високого рівня, що вона вкотре складається з мідних дротів та пайки?

Правильна відповідь на це, наскільки я зміг визначити: « Насправді, так. Наразі випадки використання вбивць для стрілок - це FRP (подумайте, Yampa, ігри, музика та реактивні системи взагалі). Проблема, з якою стикається FRP, є значною мірою тією самою проблемою, що стоїть перед усіма іншими системами синхронних повідомлень: як з'єднати безперервний потік входів у безперервний потік виходів без скидання відповідної інформації або пружинних витоків. Ви можете моделювати потоки у вигляді списків - кілька останніх систем FRP використовують такий підхід, - але коли у вас є багато вхідних списків, керувати ними стає майже неможливо. Вам потрібно ізолювати себе від струму.

Що дозволяють стрілки в системах FRP - це склад функцій в мережі, в той же час цілком абстрагуючи будь-яке посилання на базові значення, передані цими функціями. Якщо ви новачок у FP, спочатку це може бути заплутаним, а потім вражаючим розумом, коли ви поглинули його наслідки. Ви лише нещодавно поглинули думку про те, що функції можна абстрагувати та як зрозуміти такий список, як [(*), (+), (-)]тип типу [(a -> a -> a)]. За допомогою стрілок ви можете просунути абстракцію ще одним шаром.

Ця додаткова здатність до абстрактного несе із собою свої небезпеки. З одного боку, він може підштовхнути GHC до кутових випадків, коли він не знає, що робити з припущень вашого типу. Вам доведеться бути готовим думати на рівні типу - це прекрасна можливість дізнатися про види та типи RankNType та інші подібні теми.

Є також ряд прикладів того, що я б назвав "Stupid Arrow Stunts", де кодер досягає якогось комбінатора стрілок лише тому, що він чи вона хоче показати акуратний трюк з кортежами. (Ось мій власний банальний внесок у божевілля .) Не соромтесь ігнорувати таку гарячу собаку, коли натрапляєте на неї в дикій природі.

ПРИМІТКА. Як я вже згадував вище, я родич нобі. Якщо я оприлюднив помилки вище, будь ласка, виправте мене.


2
Я щасливий, що ще нічого не прийняв. Дякуємо, що надали цю відповідь. Він більше орієнтований на користувачів. Приклади чудові. Суб'єктивні частини чітко визначені та врівноважені. Я сподіваюся, що люди, які підтримали це питання, повернуться і побачать це.
Саймон Бергот

Хоча стрілки, безумовно, є неправильним інструментом для вашого зв’язаного рішення, я відчуваю, що мені потрібно згадати, що removeAt' n = arr(\ xs -> (xs,xs)) >>> arr (take (n-1)) *** arr (drop n) >>> arr (uncurry (++)) >>> returnAможна сказати більш стисло та чітко removeAt' n = (arr (take $ n-1) &&& arr (drop n)) >>> (arr $ uncurry (++)).
cemper93

29

Це своєрідна "м'яка" відповідь, і я не впевнений, чи якась посилання насправді говорить про це таким чином, але ось як я придумав стрілки:

Тип стрілки A b c- це в основному функція, b -> cале з більшою структурою так само, як монадичне значення M aмає більшу структуру, ніж звичайне старе a.

Тепер, яка ця додаткова структура буде, залежить від конкретного екземпляра стрілки, про який ви говорите. Так само, як і у монад, IO aі Maybe aкожен має різну додаткову структуру.

Те, що ви отримуєте з монадами, - це неможливість переходити з « M aдо» a. Тепер це може здатися обмеженням, але насправді це особливість: система типу захищає вас від перетворення монадичного значення у звичайне старе значення. Ви можете скористатися цим значенням, лише взявши участь у монаді через >>=або примітивні операції конкретного монадного екземпляра.

Так само, що ви отримуєте від A b cцього, це неможливість побудувати нову b-споживчу c-продукуючу "функцію". Стрілка захищає вас від споживання bта створення cвиключення, беручи участь у різних комбінаторах стрілок або за допомогою примітивних операцій конкретного екземпляра стрілки.

Наприклад, функції сигналу в Ямпа є приблизно (Time -> a) -> (Time -> b), але додатково вони повинні підкорятися певній обмеженості причинності : вихідний час tвизначається минулими значеннями вхідного сигналу: ви не можете дивитися в майбутнє. Тож те, що вони роблять, це замість того, щоб програмувати (Time -> a) -> (Time -> b), ви програмуєте SF a bі будуєте свої сигнальні функції з примітивів. Буває так, що оскільки SF a bповодиться дуже як функція, тож спільна структура - це те, що називається «стрілка».


"Стрілка захищає вас від споживання bта створення cвиключення, беручи участь у різних комбінаторах стрілок або за допомогою примітивних операцій конкретного екземпляра стрілки." З вибаченнями за відповідь на цю давню відповідь: це речення змусило мене думати про лінійні типи, тобто про те, що ресурси не можна клонувати чи зникати. Як ви думаєте, може бути якийсь зв’язок?
glaebhoerl

14

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

Без Монад або Стрілок (і Функторів) склад функцій у функціональній мові обмежується застосуванням однієї функції до результату іншої функції. За допомогою монад і функторів ви можете визначити дві функції, а потім написати окремий багаторазовий код, який визначає, як ці функції в контексті конкретної монади взаємодіють між собою та з даними, що передаються в них. Цей код розміщується в коді прив'язки Монади. Таким чином, монада - це один погляд, просто контейнер для багаторазового прив'язування коду. Функції складаються по-різному в контексті однієї монади від іншої.

Простий приклад - монада "Можливо", де в функції зв'язування є код, який, якщо функція А складається з функції В в межах монади "Можливо", а В створює "Ніщо", то код прив'язки забезпечить, щоб композиція дві функції виводять Ніщо, не намагаючись застосувати А до значення Ніщо, що виходить з B. Якщо не було монади, програмісту доведеться записати код в A, щоб перевірити наявність входу Нічого.

Монади також означають, що програмісту не потрібно чітко вводити параметри, які вимагає кожна функція, у вихідний код - функція зв'язування обробляє передачу параметра. Отже, використовуючи монади, вихідний код може починати більше нагадувати статичну ланцюжок імен функцій, а не виглядати так, ніби функція A "викликає" функцію B з параметрами C і D - код починає більше нагадувати електронну схему, ніж рухома машина - більш функціональна, ніж імперативна.

Стрілки також з'єднують функції разом із функцією прив'язки, забезпечуючи функціональність багаторазового використання та приховуючи параметри. Але самі Стрілки можуть бути з'єднані разом і складені, і вони необов'язково можуть перенаправляти дані до інших Стрілок під час виконання. Тепер ви можете застосувати дані до двох шляхів стрілок, які "роблять різні речі" до даних, і зібрати результат. Або ви можете вибрати, до якої гілки Стрілки передати дані, залежно від певного значення в даних. Отриманий код ще більше схожий на електронну схему з перемикачами, затримками, інтеграцією і т. Д. Програма виглядає дуже статично, і ви не повинні мати можливість бачити, як багато маніпуляцій із даними відбувається. Існує все менше і менше параметрів, про які можна думати, і менше потрібно думати про те, які параметри значень можуть приймати чи не приймати.

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

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


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

3

Просто доповнення до інших відповідей: Особисто мені це дуже допомагає зрозуміти, що таке поняття (математично) та як воно пов'язане з іншими мені відомими поняттями.

Що стосується стріл, то я вважав корисним наступний документ - у ньому порівнюються монади, додаткові функтори (ідіоми) та стрілки: Ідіоми не впадають у відповідь, стрілки - прискіпливі, монади - розмиті Сем Ліндлі, Філіп Вадлер та Джеремі Яллоп.

Також я вважаю, що ніхто не згадував про це посилання, яке може дати вам деякі ідеї та літературу з цього приводу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.