Doge
а можешь привести какой-нибудь кейс, где может такая штука понадобиться?
Когда хочется обходить рекурсивные структуры данных без явного использования и написания рекурсии, а лишь используя библиотечные функции
Henry
а можешь привести какой-нибудь кейс, где может такая штука понадобиться?
Там gist'ы уже мёртвые. Если нужно, могу найти исходную проблему и решение. Но когда за машиной буду.
Mikhαil
Хз, мне нравится идея собирать самому - тогда ты знаешь что и зачем ты притащил. И тащишь зависимости по потребности. Да придётся все настроить - но тебе в норм проекте все равно придётся
Kirill
Там gist'ы уже мёртвые. Если нужно, могу найти исходную проблему и решение. Но когда за машиной буду.
да как то неловко напрягать, мне просто любопытство удовлетворить
Mikhαil
Все эти темплейты - от лукавого для хелловорлдов
Mikhαil
Но мб я dead-perdead
Henry
Кстати, была статья на Хабре.
Henry
Для удовлетворения любопытства самое то.
Kirill
спс
Vasiliy
Критерий
https://m.habr.com/ru/post/57503/
разве это настоящий катаморфизм? тот ведь один на любой функтор под Fix'ом
Критерий
это какие-то частные свёртки для разных типов
Doge
да как то неловко напрягать, мне просто любопытство удовлетворить
data Tree a = Leaf a | Branch (Tree a) (Tree a) -- Обычный явный вариант, например для вычисления например суммы элементов: sum (Leaf a) = a sum (Branch left right) = (sum left) + (sum right) -- И для вычисления глубины: depth (Leaf a) = 1 depth (Branch left right) = 1 + max (depth left) (depth right) -- тут нам явно пришлось писать рекурсивные функции, причем сама рекурсия в обоих функциях повторияется -- а хотелось бы, чтобы можно было саму эту рекурсивную часть выделить отдельно и её переиспользовать -- И тут нам на помощь как раз придут катаморфизмы -- Теперь опишем необходимые нам вещи (они обычно в либах) -- Тип, который позволит нам в дальнейшем описать рекурсивный тип на основе нерекурсивного newtype Fix f = Fix { unFix :: f (Fix f) } -- Непосредственно катаморфизм -- Эта функция позволяет для любого рекурсивного типа отделить свертку и сам процесс рекурсии -- При этом она обобщена как и по тому как мы сворачиваем, так и какой тип мы сворачиваем cata :: Functor f => (f a -> a) -> (Fix f -> a) cata alg = alg . fmap (cata alg) . unFix -- Теперь описываем наш тип как нерекурсивный, заменяя все рекурсивные части на доп дженерик параметр -- И создаем инстанс функтора для него data TreeF a f = LeafF a | BranchF f f deriving Functor -- Теперь мы можем описать сумму и глубину, как нерекурсивную функцию вида TreeF Int Int -> Int sumAlgebra (LeafF a) = a sumAlgebra (BranchF left right) = left + right depthAlgebra (LeafF a) = 1 depthAlgebra (BranchF left right) = 1 + max left right -- И чтобы получить функцию мы воспользуемся библиотечными примитивами так, что в итоге нам явно рекурсию писать не придется -- Аналогом исходного дерева будет такой синоним: type Tree' a = Fix (TreeF a) -- И чтобы получить сумму или глубину по такому дереву достаточно вызвать функцию cata + выше определнную sumAlgebra или depthAlgbera sum' = cata sumAlgebra depth' = cata depthAlgebra
Критерий
https://bartoszmilewski.com/2013/06/10/understanding-f-algebras/
Sergey
data Tree a = Leaf a | Branch (Tree a) (Tree a) -- Обычный явный вариант, например для вычисления например суммы элементов: sum (Leaf a) = a sum (Branch left right) = (sum left) + (sum right) -- И для вычисления глубины: depth (Leaf a) = 1 depth (Branch left right) = 1 + max (depth left) (depth right) -- тут нам явно пришлось писать рекурсивные функции, причем сама рекурсия в обоих функциях повторияется -- а хотелось бы, чтобы можно было саму эту рекурсивную часть выделить отдельно и её переиспользовать -- И тут нам на помощь как раз придут катаморфизмы -- Теперь опишем необходимые нам вещи (они обычно в либах) -- Тип, который позволит нам в дальнейшем описать рекурсивный тип на основе нерекурсивного newtype Fix f = Fix { unFix :: f (Fix f) } -- Непосредственно катаморфизм -- Эта функция позволяет для любого рекурсивного типа отделить свертку и сам процесс рекурсии -- При этом она обобщена как и по тому как мы сворачиваем, так и какой тип мы сворачиваем cata :: Functor f => (f a -> a) -> (Fix f -> a) cata alg = alg . fmap (cata alg) . unFix -- Теперь описываем наш тип как нерекурсивный, заменяя все рекурсивные части на доп дженерик параметр -- И создаем инстанс функтора для него data TreeF a f = LeafF a | BranchF f f deriving Functor -- Теперь мы можем описать сумму и глубину, как нерекурсивную функцию вида TreeF Int Int -> Int sumAlgebra (LeafF a) = a sumAlgebra (BranchF left right) = left + right depthAlgebra (LeafF a) = 1 depthAlgebra (BranchF left right) = 1 + max left right -- И чтобы получить функцию мы воспользуемся библиотечными примитивами так, что в итоге нам явно рекурсию писать не придется -- Аналогом исходного дерева будет такой синоним: type Tree' a = Fix (TreeF a) -- И чтобы получить сумму или глубину по такому дереву достаточно вызвать функцию cata + выше определнную sumAlgebra или depthAlgbera sum' = cata sumAlgebra depth' = cata depthAlgebra
я надеюсь ты нее отруки это сюда писал
Doge
я надеюсь ты нее отруки это сюда писал
Да это пару минут написать
Alex
Alex
Vasiliy
четко
Mikhαil
Похоже на египетские рисунки
Возрождаем наскальную живопись итт
Mikhαil
Тысячелетия прогресса чтобы в итоге опять к наскальной живописи прийти
Anonymous
Возрождаем наскальную живопись итт
Это в теоркате называется «архоморфизм»
Vasiliy
имхо, когда то мы придем к тому чтобы писать иероглифами имхо
Mikhαil
имхо, когда то мы придем к тому чтобы писать иероглифами имхо
Ну Китай то разрешил теперь три ребёнка в семье
Mikhαil
Так что это не имхо даже
Mikhαil
Ilya
Не от хорошей жизни разрешил.
Vasiliy
я не про китайский, а что уйдем от фонетики букв
Ilya
Ну хз. А зачем?
Потому что спираль!!111
Romɑn
https://twitter.com/mithridates/status/1399304617251405830?s=09
Ayrat
Короче, сидел писал, писал приложение. Решил подключить DI, потому что зависимостей уже стало много, ручками собирать заебался. Раньше я работал с дубовым как полено Guice для джавы, он фичастый, но мне много не надо. Сейчас решил попробовать kotlin-first experience - взял модный Koin Вроде работает, но на CI тесты стали flaky, но хотя бы сразу понял что Koin говнит
Ayrat
так вот, эти педики в 2021 делают регистрацию в глобальный контекст даже если я делааю локальный
Ayrat
потому что нереализовано
Ayrat
То есть в одних тестах у меня один мок регается и стартуется этот ебучий Koin в других тестах другой мок и стартуется этот Koin ещё раз (В ТОТ ЖЕ ИНСТАНС ЧТО И ПЕРВЫЙ БЛЯТЬ)
Ayrat
И кто успел мок зарегать, тот и папка
Ayrat
Это как бы дефолт
Ayrat
если твои тесты не работают в многопотоке - иди в проституки сразу
Ilya
Ну естесна
У меня тоже был, но потом все таки пришлось отказаться в некоторых местах
Ayrat
Короче, нашёл я ишую, ей больше года, видимо никому кроме меня не нужны многопоточные тесты
Ilya
если твои тесты не работают в многопотоке - иди в проституки сразу
А там уровень параллелизма какой ? Класс, коллекция, отдельный тест?
Ilya
отдельный тест
Опасные ребята
Ayrat
Опасные ребята
это у меня такой закладывается. а эта хуита не умеет ни в какой параллелизм
Ayrat
потому что надо в одном классе отработать тесты с одними моками, потом в другой идти
Ayrat
я ж состарюсь
Ayrat
Думаешь почему параллельные тесты редкие?
Не знаю, у меня всё работало на ручном DI
Ayrat
Короче, придется откатывать эту хуиту и брать старый добрый Guice пусть он и не модный
Denis
... придётся откатывать этот котлин, и брать джаву, хоть она и не модная
Denis
😂😂
Denis
https://github.com/Kodein-Framework/Kodein-DI вот еще есть
Denis
и там много всяких разных DI типо
Ayrat
А какой быстрее?
хз, не нашёл таких бенчей
Ayrat
Guice не то чтобы очень быстрый. Вот так бы я сказал. Но и далеко не самый медленный
Ayrat
Это вот к ебучей либе которая ебашит инстансы в глобальный контекст
Ilya
Проплачено?😱
Ayrat
Ну почему люди такие говноеды. вот тут типа специальный контейнер для теста с локальными оверрайдами создаётся. на каждый тест или класс тестов такой можно создавать. И вот в инстанс _koin кладётся вызов startKoin() https://github.com/InsertKoinIO/koin/blob/master/core/koin-test-junit4/src/main/kotlin/org/koin/test/KoinTestRule.kt#L39 Который идёт в статичный глобальный контекст, и от него стартует Koin https://github.com/InsertKoinIO/koin/blob/d9fdc2266d03ac64c6e7c3946046a052993d8dae/core/koin-core/src/jvmMain/kotlin/org/koin/core/context/GlobalContext.kt#L56-L60 ну просто нет слов насколько хуёво сделано.
Ayrat
бля -_-
Ilya
пащиму
Пропаганда депенденси реджекшн.
Ilya
Там боты в основной набежали, кстати. Можно тестить аватарки.
Ayrat
Хоспади какая же уёбская библиотека этот Koin Щас будет немного боли и страданий. Вот там короче есть модули, где можно объявлять свои депенденси. Вот как-то так val testModule = module { single { someService as SomeInterface } } я короче починил ебучую параллелизацию тем что скопировал из библы контексты и сделал его не синглтоном и создаю вообще всё с нуля для каждого теста. Казалось бы, где может быть подвох? А вот оказалось что когда контекст Koin грузит модуль в себя он в МОДУЛЕ проставляет флаг isLoaded (мутирует модуль, да) И далее следующий контекст Koin берёт тот же инстанс модуля, чекает флаг и молча НЕ ГРУЗИТ ЕГО, т.к. блять if(module.IsLoaded) сука true Я себе уже все волосы на мошонке вырвал от того что не понимал какого хуя ничего не работает. Ну пока вообще всё не передебажил на свете. Ух блять, какой говноедский софт.
Ayrat
Ну понятно починю так fun testModule() = module { single { someService as SomeInterface } } то есть теперь на каждый контекст Koin будет ещё и модуль свой создаваться, их оказывается нельзя переиспользовать. Ебать идиотизм
Mark
сделай пр
Mark
спаси малюток
Ayrat
сделай пр
да там надо атомную бомбу засылать чтобы сжечь всё нахуй
Ayrat
у меня целый день горит уже
Ayrat
авторы сделали всё чтобы я не посмотрел сегдоня ютуб.
Ilya
А это разве не решение? https://github.com/InsertKoinIO/koin/issues/613