Пользователь 'singpolyma' спросил reddit, если была какая-то общая структура, лежащая в основе:
data FailList a e = Done | Next a (FailList a e) | Fail e
Была предложена свободная монада, но я подумал, можно ли ее смоделировать в более общем плане с помощью аппликативных функторов. В Abstracting with Applicatives Базерман показывает нам, что сумма двух аппликативных функторов также является аппликативным функтором с смещением влево/вправо, если мы имеют естественное преобразование в направлении смещения. Это похоже на то, что нам нужно! Таким образом, я начал свое предложение, но потом быстро столкнулся с проблемами. Может ли кто-нибудь увидеть решения этих проблем?:
Во-первых, мы начнем с определения суммы двух функторов. Я начал здесь, потому что мы хотим моделировать типы сумм - либо успехи, либо успехи, и неудачу.
data Sum f g a = InL (f a) | InR (g a)
И два функтора, с которыми мы хотим работать:
data Success a = Success [a]
data Failure e a = Failure e [a]
Success
прямолинейный - по существу Const [a]
. Однако Failure e
я не уверен. Это не аппликативный функтор, потому что pure
не имеет никакого определения. Это, однако, экземпляр Apply:
instance Functor Success where
fmap f (Success a) = Success a
instance Functor (Failure e) where
fmap f (Failure e a) = Failure e a
instance Apply (Failure e) where
(Failure e a) <.> (Failure _ b) = Failure e a
instance Apply Success where
(Success a) <.> (Success b) = Success (a <> b)
instance Applicative Success where
pure = const (Success [])
a <*> b = a <.> b
Затем мы можем определить сумму этих функторов с естественным преобразованием справа налево (поэтому левое смещение):
instance (Apply f, Apply g, Applicative g, Natural g f) => Applicative (Sum f g) where
pure x = InR $ pure x
(InL f) <*> (InL x) = InL (f <*> x)
(InR g) <*> (InR y) = InR (g <*> y)
(InL f) <*> (InR x) = InL (f <.> eta x)
(InR g) <*> (InL x) = InL (eta g <.> x)
И единственное, что нам теперь нужно сделать, это определить наше естественное преобразование, и именно здесь все рушится.
instance Natural Success (Failure e) where
eta (Success a) = Failure ???? a
Невозможность создания Failure
кажется проблемой. Кроме того, даже быть взломанным и использовать ⊥ не является вариантом, потому что это будет оценено, в случае, если у вас есть InR (Success ...) <*> InL (Failure ...)
.
Я чувствую, что у меня что-то не хватает, но я понятия не имею, что это такое.
Можно ли это сделать?