Ilya
Alexander
Автоматически вывести, думаю, нельзя. Ну можно попробовать для твоего типа задерайвить функтор, просто если он нетривиальный, может не то получиться
Ilya
функтор дерайвится (там ньютайп вокруг функции), а вот аппликатив уже не хочет
Ilya
даже с GeneralizedNewtypeDeriving
Alexander
Пусть будет ручками написан, это норм
Alexander
А для нижележащего типа что определено?
Ilya
Alexander
Принято выражать монаду через эти понятия. В обратном направлении идти неправильно (хоть и можно)
Dmitry
Сегодня день уклончивых ответов
Vladimir
Ilya
Разве аппликатив и функтор нынче не в зависимостях монады?
в зависимостях. поэтому и пришлось написать
instance Applicative where
pure = return
(<*>) = ap
instance Functor where
fmap = ap . return
но этот код выглядит как что-то, что можно сделать автоматически. слишком общий. Поэтому и спрашиваю, можно ли его сделать как-то автоматически.
Aleksei (astynax)
Автоматически делать плохое?
Aleksei (astynax)
Есть естетсвенная последовательность F->A->M и последующее должно выражаться, через предыдущее, а не наоборот
Vladimir
Мне не очевидно, что он сработает. А если сработает, то не очевидно, что будет работать так, как задумано.
Aleksei (astynax)
Вот выпилят return из Monad и сделают алиасом для pure, и неправильные инстансы превратятся в тыквы
Ilya
Aleksei (astynax)
Выражать return через pure - норма. Но не наоборот
Ilya
Ilya
Ilya
и заодно с fmap, который равн ap . return
Ilya
не понимаю, почему вы защищаете ситуацию, когда программист вынужден писать бойлерплейт
Aleksei (astynax)
Да блин. Это ap "равен" fmap с точностью до return
Ilya
Aleksei (astynax)
Functor'ов сильно больше, чем монад (инстансов). И выражать общее через частное - туповато
Ilya
"туповато" это всё?:)
Ilya
речь идёт о соблюдении DRY, всего-то
Aleksei (astynax)
И вообще, DRY головного мозга какой-то :)
Aleksei (astynax)
Все Монады - Функторы, но не наоборот. Поэтому равенство как минимум по смыслу не коммутативно
Ilya
Aleksei (astynax)
К тому же есть ещё устоявшиеся практики.
Ilya
а "равенство, не коммутативно по смыслу" это от меня ускользает
Aleksei (astynax)
Кароч, если большинство посчитает, что выражать функтор через монаду, это "ок" - то пусть его. Но я лично сомневаюсь, что так будет. А я самоустраняюсь - нечего ещё и в выходной в чатик тупить
Vladimir
https://hackage.haskell.org/package/base-4.8.0.0/docs/src/GHC-Base.html
Vladimir
return :: a -> m a
return = pure
Kirill
+1 за монаду из функтора
Vladimir
по крайней мере бойлерплейт return = pure пейсать не надо :)
Cheese
Ilya
Кароч, если большинство посчитает, что выражать функтор через монаду, это "ок" - то пусть его. Но я лично сомневаюсь, что так будет. А я самоустраняюсь - нечего ещё и в выходной в чатик тупить
Я сам за то, чтобы писать инстансы в "естественной" (твоей) последовательности. Но только там, где это не приводит к бойлерплейту. Например в случае Semigroup => Monoid. А вот в Applicative => Monad тебе по сути два раза приходится описывать, как комбинируется твой побочный эффект, понимаешь? Сначала для Applicative, а потом ещё в Monad. Хотя достаточно описать только в Monad, после чего сделать <*> = ap.
Ilya
по крайней мере бойлерплейт return = pure пейсать не надо :)
спасибо, принято! теперь у меня это выглядит так:
instance Monad where
(>>=) = (тут "существенный" код)
instance Applicative where
pure = (тут "существенный" код)
(<*>) = ap
instance Functor where
fmap = ap . return
Ilya
^ а если писать в обратном порядке, то "существенных" кодов будет не 2, а все 4
Vladimir
Вот как bind с ap развязать -- это вопрос непростой.
Vladimir
Я бы сделал это отдельной функцией, да простят меня боги за это.
Sergey
доброго времени суток! кто-нибудь знает, как сделать это без лапши?
f :: Either Error Result
g :: Result -> Either AnotherError AnotherResult
h :: AnotherResult -> Either ThirdErrorType EndResult
composed =
case f of
Left err -> print err
Right a ->
case g a of
Left err -> print err
Right b ->
case h b of
Left err -> print err
Right result -> pure result
IC
каким-таким?
"от стека только проблемы, берите кабал-инстале"
Alexander
Монада же
Sergey
Именно
Alexander
Alexander
Ну написать комбинатор, который ошибку обобщенную принтит
IC
Монада же
Же, но надо пользоваться fmapL из errors чтобы всех в один тип свести.
Alexander
И все делать через него в монаде Either
Alexander
IC
Sergey
fmapL звучит вроде логично
Ilya
Aragaer
тип ошибок разный, но везде Either, ошибка слева и ее можно (и нужно) печатать
Aragaer
поэтому если бы императивно, то я бы в цикле разобрал, а так может рекурсивно сделать
Sergey
Но тогда получается в каждом месте надо вставлять fmapL show, чтобы тип стал string везде. С этим все ясно. А есть ли способ объединить эти 3 типа ошибок в 1 и отметить эти функции как Either UnionError блаблабла?
Alexander
IC
Всё равно fmapL
Alexander
можно случайно реализовать Monad через applicative
Alexander
если не свое делаешь
Alexander
а если свое то можно 5 строк скопипастить
IC
Или сами функции завернуть чтобы сразу правильный тип имели.
Alexander
попрошу не приписывать мне свое странное понимание моих соов
Sergey
Не можно, это 3 функции из разных библиотек
Cheese
Alexander
а почему я считаю hpack говном и что в нем хорошего, я там полчаса расписывал
Ilya
а если свое то можно 5 строк скопипастить
просто вот этот копипаст и раздражает. и возможность ошибиться в копипасте, и сделать liftA2 /= liftM2, или даже fmap /= ap . return. Но я мысль понял, что ж, придётся значит оставить так.
Alexander
f :: Either String String
f = undefined
g :: Result -> Either Int Int
g = undefined
h :: AnotherResult -> Either (String, Int) (String, Int)
h = undefined
withError :: Show e => Either e a -> (a -> b) -> IO b
withError (Left err) f = print err
withError (Right a) f = pure $ f a
composed = do
a <- withError () (const f)
b <- withError a g
withError b h
На компиляние или работоспособность не проверял, но идея должна быть понятна
UPD: Исправил комбинатор.
IC
Alexander