Alexander
Автоматически вывести, думаю, нельзя. Ну можно попробовать для твоего типа задерайвить функтор, просто если он нетривиальный, может не то получиться
Ilya
функтор дерайвится (там ньютайп вокруг функции), а вот аппликатив уже не хочет
Ilya
даже с GeneralizedNewtypeDeriving
Alexander
Пусть будет ручками написан, это норм
Ilya
Пусть будет ручками написан, это норм
ок, просто хотел узнать как принято. спасибо.
Alexander
А для нижележащего типа что определено?
Alexander
Принято выражать монаду через эти понятия. В обратном направлении идти неправильно (хоть и можно)
Dmitry
Сегодня день уклончивых ответов
Ilya
Разве аппликатив и функтор нынче не в зависимостях монады?
в зависимостях. поэтому и пришлось написать instance Applicative where pure = return (<*>) = ap instance Functor where fmap = ap . return но этот код выглядит как что-то, что можно сделать автоматически. слишком общий. Поэтому и спрашиваю, можно ли его сделать как-то автоматически.
Aleksei (astynax)
Автоматически делать плохое?
Ilya
Автоматически делать плохое?
а что плохого в таком коде?
Aleksei (astynax)
Есть естетсвенная последовательность F->A->M и последующее должно выражаться, через предыдущее, а не наоборот
Vladimir
Мне не очевидно, что он сработает. А если сработает, то не очевидно, что будет работать так, как задумано.
Aleksei (astynax)
Вот выпилят return из Monad и сделают алиасом для pure, и неправильные инстансы превратятся в тыквы
Aleksei (astynax)
Выражать return через pure - норма. Но не наоборот
Ilya
Выражать return через pure - норма. Но не наоборот
а с <*> что делать будем? который равен ap
Ilya
и заодно с fmap, который равн ap . return
Ilya
не понимаю, почему вы защищаете ситуацию, когда программист вынужден писать бойлерплейт
Aleksei (astynax)
Да блин. Это ap "равен" fmap с точностью до return
Aleksei (astynax)
Functor'ов сильно больше, чем монад (инстансов). И выражать общее через частное - туповато
Ilya
"туповато" это всё?:)
Ilya
речь идёт о соблюдении DRY, всего-то
Aleksei (astynax)
И вообще, DRY головного мозга какой-то :)
Ilya
И вообще, DRY головного мозга какой-то :)
понятно. подожду, что скажут другие участники
Aleksei (astynax)
Все Монады - Функторы, но не наоборот. Поэтому равенство как минимум по смыслу не коммутативно
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 пейсать не надо :)
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
Монада же
IC
Монада же
Тип ошибок разный
Sergey
Именно
Alexander
можно как-нибудь Applicative и Functor автоматически вывести из Monad? Хочу удалить такой код instance Applicative where pure = return (<*>) = ap instance Functor where fmap = ap . return
была идея экспешнена который позволил бы определять только Monad и получить все, но в общем случае нельзя
Alexander
Ну написать комбинатор, который ошибку обобщенную принтит
IC
Монада же
Же, но надо пользоваться fmapL из errors чтобы всех в один тип свести.
Alexander
И все делать через него в монаде Either
Alexander
"от стека только проблемы, берите кабал-инстале"
можно ссылкой на цитаты, а не вольную интерпретацию?
Cheese
А как в Vector сделать атомарное инкрементирование? succ справится? Компилятор сделает его атомарным?
кажется, я вспоминал эту статью https://codeburst.io/the-haskell-concurrency-primitive-shootout-538c21993f1c правда, здесь нет ничего про векторы, поищу ещё
Ilya
была идея экспешнена который позволил бы определять только Monad и получить все, но в общем случае нельзя
тут есть какие-то подводные грабли, почему так нельзя делать всегда автоматически — считать определенным Applicative и Functor, если написан Monad?
Sergey
fmapL звучит вроде логично
Ilya
тут есть какие-то подводные грабли, почему так нельзя делать всегда автоматически — считать определенным Applicative и Functor, если написан Monad?
по-моему обратный вариант (который отстаивал @astynax) наоборот может привести к проблемам, вплоть до того, что liftA2 /= liftM2 и т.д.
Aragaer
тип ошибок разный, но везде Either, ошибка слева и ее можно (и нужно) печатать
Aragaer
поэтому если бы императивно, то я бы в цикле разобрал, а так может рекурсивно сделать
Sergey
Но тогда получается в каждом месте надо вставлять fmapL show, чтобы тип стал string везде. С этим все ясно. А есть ли способ объединить эти 3 типа ошибок в 1 и отметить эти функции как Either UnionError блаблабла?
IC
Всё равно fmapL
Alexander
можно случайно реализовать Monad через applicative
Alexander
если не свое делаешь
Alexander
а если свое то можно 5 строк скопипастить
IC
Или сами функции завернуть чтобы сразу правильный тип имели.
Alexander
Например так.
там нету ни одного слова про стек
Alexander
попрошу не приписывать мне свое странное понимание моих соов
Sergey
Не можно, это 3 функции из разных библиотек
IC
там нету ни одного слова про стек
Про про другой инструмент есть, после чего последовал очередной срач.
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: Исправил комбинатор.
Alexander
возможно, Vector выиграл в 1-нитевом режиме
это не удивительно все остальные имеют оверхед на синхронизацию или атомарность
IC
а почему я считаю hpack говном и что в нем хорошего, я там полчаса расписывал
А мог бы и не рассказывать, если бы первый наброс не был таким едким.
Alexander
А мог бы и не рассказывать, если бы первый наброс не был таким едким.
не мог конечно, чтов первый раз разговор про hpack был