Наверное, я как-то криво выразился. Не нужно композить два чёрных ящика (box Error, с anyhow::Error). Нужно композить два белых (конкретные Result<FooError, _>, Result<BarError, _>) в один чёрный. И как только вы это сделали, объединили Result<FooError, T> с Result<BarError, T> в Result<anyhow::Error, T>, вы потеряли вообще всю информацию, какие конкретно ошибки могут там быть. Это всё равно, что хаскелевый SomeException
Я, кстати, не вижу фундаментальных причин, по которым HasCatch из capability
Функциональные зависимости всё портят. Хотя в этом случае я даже не особо понимаю, как оно там считается
data Foo = Foo deriving (Show, Exception)
data Bar = Bar deriving (Show, Exception)
throwCap :: forall a m b. Cap.HasThrow a a m => a -> m b
throwCap = Cap.throw @a
type CanThrow a = Cap.HasThrow a a
foo :: (CanThrow Bar m, CanThrow Foo m) => m ()
foo = do
() <- throwCap Foo
throwCap Bar
catchCap :: (Unlift.MonadUnliftIO m, Exception e) => Cap.MonadCatch e m a -> (e -> m a) -> m a
catchCap (Cap.MonadCatch m) = Unlift.catch m
baz :: CanThrow Bar m => m ()
baz = foo `catchCap` \Foo -> pure ()
• Couldn't match type ‘Foo’ with ‘Bar’
arising from a functional dependency between:
constraint ‘HasThrow Bar Bar (MonadCatch Foo m)’
arising from a use of ‘foo’
instance ‘HasThrow tag e (MonadCatch e m1)’ at <no location info>
• In the first argument of ‘catchCap’, namely ‘foo’
In the expression: foo `catchCap` \ Foo -> pure ()
In an equation for ‘baz’: baz = foo `catchCap` \ Foo -> pure ()
|
xxx | baz = foo `catchCap` \Foo -> pure ()
| ^^^
Проблема Result в том, что когда они используется, как есть (без box Error, failure, anyhow), то он не композится с другими Result. Именно поэтому и придумали failure и anyhow. Однако их проблема уже в другом. Как только ты забоксил ошибку в трейт Error (или обернул в anyhow::Error), ты понятия не имеешь, что за ошибка лежит внутри. Два стула: либо не композится, как MonadError/ExceptT либо неизвестность, как с голыми исключениями.
Пробовал?
А Вы точно читали этот текст дальше наброса на раст?
Наверное, я как-то криво выразился. Не нужно композить два чёрных ящика (box Error, с anyhow::Error). Нужно композить два белых (конкретные Result<FooError, _>, Result<BarError, _>) в один чёрный. И как только вы это сделали, объединили Result<FooError, T> с Result<BarError, T> в Result<anyhow::Error, T>, вы потеряли вообще всю информацию, какие конкретно ошибки могут там быть. Это всё равно, что хаскелевый SomeException
Так ето ты скопипасти, да проверь, что оно неюзабельно, куда ни добавляй)
А куда ты его добавишь-то?
Функциональные зависимости всё портят. Хотя в этом случае я даже не особо понимаю, как оно там считается
Проблема Result в том, что когда они используется, как есть (без box Error, failure, anyhow), то он не композится с другими Result. Именно поэтому и придумали failure и anyhow. Однако их проблема уже в другом. Как только ты забоксил ошибку в трейт Error (или обернул в anyhow::Error), ты понятия не имеешь, что за ошибка лежит внутри. Два стула: либо не композится, как MonadError/ExceptT либо неизвестность, как с голыми исключениями.
Да, так сделать можно (я про Named), я пробовал. Но типы становятся слишком вербозными и чаще бесполезными, чем полезными.