Я хотів би запропонувати більш систематичний підхід до відповіді на це запитання, а також показати приклади, які не використовують жодних спеціальних хитрощів, таких як "найнижчі" значення чи нескінченні типи даних чи щось подібне.
Коли у конструкторів типів відсутні екземпляри класу типу?
Загалом, є дві причини, чому конструктор типів не може мати примірник певного класу типу:
- Неможливо реалізувати підписи типів необхідних методів із класу типу.
- Може реалізувати підписи типів, але не може задовольнити необхідні закони.
Приклади першого типу простіші за типи другого роду, тому що для першого типу нам просто потрібно перевірити, чи можна реалізувати функцію з підписом заданого типу, тоді як для другого роду нам потрібно довести, що жодної реалізації могло б задовольнити закони.
Конкретні приклади
Це контрафунктор, а не функтор щодо параметра типу a, тому що aв противаріантному положенні. Неможливо реалізувати функцію з підписом типу (a -> b) -> F z a -> F z b.
Конструктор типів, який не є законним функціонером, навіть якщо підпис типу fmapможе бути реалізований:
data Q a = Q(a -> Int, a)
fmap :: (a -> b) -> Q a -> Q b
fmap f (Q(g, x)) = Q(\_ -> g x, f x) -- this fails the functor laws!
Цікавим аспектом цього прикладу є те, що ми можемо реалізувати fmapправильний тип, навіть Fне може бути функтором, оскільки він використовує aв протилежній позиції. Таким чином, ця реалізація, fmapпоказана вище, вводить в оману - навіть якщо вона має правильний підпис типу (я вважаю, що це єдина можлива реалізація підпису цього типу), закони функтора не задовольняються. Наприклад, fmap id≠ id, тому що let (Q(f,_)) = fmap id (Q(read,"123")) in f "456"є 123, але let (Q(f,_)) = id (Q(read,"123")) in f "456"є456 .
Насправді Fце лише профунктор, - він не є ні функтором, ні контрафунктором.
Законний функтор, який не застосовується, оскільки підпис типу pureне може бути реалізований: візьміть монаду Writer (a, w)і усуньте обмеження, яке wповинно бути моноїдом. Тоді неможливо побудувати значення типу (a, w)з a.
Функтор , яка не апплікатівен , так як тип підпис <*>не може бути реалізована: data F a = Either (Int -> a) (String -> a).
Функтор, який не є законним застосунком, незважаючи на те, що методи класу типу можуть бути реалізовані:
data P a = P ((a -> Int) -> Maybe a)
Конструктор типу P- це функтор, оскільки він використовується aлише в коваріантних положеннях.
instance Functor P where
fmap :: (a -> b) -> P a -> P b
fmap fab (P pa) = P (\q -> fmap fab $ pa (q . fab))
Єдина можлива реалізація підпису типу <*>- це функція, яка завжди повертає Nothing:
(<*>) :: P (a -> b) -> P a -> P b
(P pfab) <*> (P pa) = \_ -> Nothing -- fails the laws!
Але ця реалізація не відповідає закону про ідентичність для прикладних функціонерів.
- Функтор, який є,
Applicativeале не є,Monad тому що підпис типу bindне може бути реалізований.
Я не знаю таких прикладів!
- Функтор, який є,
Applicativeале не є,Monad тому що закони не можуть бути виконані, навіть якщо підпис типу bindможе бути реалізований.
Цей приклад породив досить багато дискусій, тому можна з упевненістю сказати, що довести цей приклад правильним непросто. Але кілька людей це перевірили самостійно різними методами. Див. `Дані PoE a = Порожня | Пара aa` монада? для додаткового обговорення.
data B a = Maybe (a, a)
deriving Functor
instance Applicative B where
pure x = Just (x, x)
b1 <*> b2 = case (b1, b2) of
(Just (x1, y1), Just (x2, y2)) -> Just((x1, x2), (y1, y2))
_ -> Nothing
Дещо громіздко довести, що не існує законної Monadінстанції. Причина немональної поведінки полягає в тому, що не існує природного способу реалізації, bindколи функція f :: a -> B bможе повернутися Nothingабо Justдля різних значеньa .
Можливо, зрозуміліше врахувати Maybe (a, a, a), що також не є монадою, і спробувати здійснити joinдля цього. Виявите, що немає інтуїтивно розумного способу реалізації join.
join :: Maybe (Maybe (a, a, a), Maybe (a, a, a), Maybe (a, a, a)) -> Maybe (a, a, a)
join Nothing = Nothing
join Just (Nothing, Just (x1,x2,x3), Just (y1,y2,y3)) = ???
join Just (Just (x1,x2,x3), Nothing, Just (y1,y2,y3)) = ???
-- etc.
У випадках, зазначених у ???, видається очевидним, що ми не можемо виготовити Just (z1, z2, z3)будь-який розумний і симетричний з шести різних типів значень a. Ми, безумовно, могли вибрати якийсь довільний підмножина з цих шести значень, - наприклад, завжди приймати перше не порожнє Maybe- але це не задовольнило б закони монади. Повернення Nothingтакож не буде задовольняти закони.
- Деревоподібна структура даних, яка не є монадою, хоча і має асоціативність,
bindале не відповідає законам ідентичності.
Звичайна деревна монада (або «дерево з гілками у формі функтора») визначається як
data Tr f a = Leaf a | Branch (f (Tr f a))
Це вільна монада над функтором f. Форма даних - це дерево, де кожна точка гілки є "функтор-фул" підрядів. Стандартне двійкове дерево було б отримане за допомогою type f a = (a, a).
Якщо ми модифікуємо цю структуру даних, створюючи також листя у формі функтора f, ми отримуємо те, що я називаю «семімонадою» - це таке, bindяке задовольняє закони природності та асоціативності, але його pureметод не відповідає одному із законів тотожності. "Семімонади - це напівгрупи в категорії ендофаніків. У чому проблема?" Це клас типу Bind.
Для простоти я визначаю joinметод замість bind:
data Trs f a = Leaf (f a) | Branch (f (Trs f a))
join :: Trs f (Trs f a) -> Trs f a
join (Leaf ftrs) = Branch ftrs
join (Branch ftrstrs) = Branch (fmap @f join ftrstrs)
Філія щеплення є стандартною, але лист щеплення не є стандартною і виробляє Branch. Це не є проблемою для закону про асоціативність, але порушує один із законів тотожності.
Коли поліноміальні типи мають монадні екземпляри?
Жоден з функціонерів Maybe (a, a)і не Maybe (a, a, a)може бути наділений законним Monadекземпляром, хоча вони, очевидно Applicative.
У цих функторів немає жодних хитрощів - ні Voidі bottomніде, немає хитрої ліні / суворості, нескінченних структур і жодних обмежень класу типів. ApplicativeПримірник повністю стандартні. Функції returnі bindможуть бути реалізовані для цих функторів, але не відповідають законам монади. Іншими словами, ці функтори не є монадами, оскільки конкретна структура відсутня (але зрозуміти, чого саме не вистачає, непросто). Наприклад, невелика зміна функтора може перетворити його в монаду: data Maybe a = Nothing | Just aце монада. Ще один подібний функторdata P12 a = Either a (a, a) - це монада.
Конструкції для поліноміальних монад
Загалом, ось деякі конструкції, які випускають законні Monadз поліноміальних типів. У всіх цих конструкціях Mє монада:
type M a = Either c (w, a)де wбудь-який моноїд
type M a = m (Either c (w, a))де mбудь-яка монада і wбудь-який моноїд
type M a = (m1 a, m2 a)де m1і m2є якісь монади
type M a = Either a (m a)де mбудь-яка монада
Перша конструкція WriterT w (Either c), друга конструкція WriterT w (EitherT c m). Третя конструкція є складовою продуктом монад: pure @Mвизначається як компонентний добуток pure @m1і pure @m2, і join @Mвизначається, опускаючи дані про поперечні продукти (наприклад m1 (m1 a, m2 a), відображається m1 (m1 a)шляхом опускання другої частини кортежу):
join :: (m1 (m1 a, m2 a), m2 (m1 a, m2 a)) -> (m1 a, m2 a)
join (m1x, m2x) = (join @m1 (fmap fst m1x), join @m2 (fmap snd m2x))
Четверта конструкція визначається як
data M m a = Either a (m a)
instance Monad m => Monad M m where
pure x = Left x
join :: Either (M m a) (m (M m a)) -> M m a
join (Left mma) = mma
join (Right me) = Right $ join @m $ fmap @m squash me where
squash :: M m a -> m a
squash (Left x) = pure @m x
squash (Right ma) = ma
Я перевірив, що всі чотири конструкції виробляють законні монади.
Я здогадуюсь, що немає інших конструкцій для поліноміальних монад. Наприклад, функтор Maybe (Either (a, a) (a, a, a, a))не отримується за допомогою будь-якої з цих конструкцій і тому не є монадичним. Тим НЕ менше, Either (a, a) (a, a, a)це Монадический тому вона ізоморфна добутку трьох монад a, aі Maybe a. Крім того, Either (a,a) (a,a,a,a)є монадичним, оскільки є ізоморфним продукту aі Either a (a, a, a).
Чотири конструкції, показані вище, дозволять нам отримати будь-яку суму будь-якої кількості продуктів будь-якої кількості a, наприклад, Either (Either (a, a) (a, a, a, a)) (a, a, a, a, a))тощо. Усі конструктори такого типу матимуть (принаймні один) Monadекземпляр.
Зрозуміло, залишається зрозуміти, які випадки використання можуть існувати для таких монад. Інша проблема полягає в тому, що Monadвипадки, отримані за допомогою конструкцій 1-4, як правило, не є унікальними. Наприклад, конструктору типу type F a = Either a (a, a)можна надати Monadекземпляр двома способами: шляхом побудови 4 за допомогою монади (a, a)та за допомогою конструкції 3 за допомогою ізоморфізму типу Either a (a, a) = (a, Maybe a). Знову ж таки, пошук випадків використання для цих реалізацій не відразу очевидний.
Залишається питання - даючи довільний тип поліноміальних даних, як розпізнати, чи має він Monadекземпляр. Я не знаю, як довести, що немає інших конструкцій для поліноміальних монад. Я не думаю, що поки що існує якась теорія, яка б відповіла на це питання.
* -> *), для якого немає відповідногоfmap?