Ignat
лучшие абстракции!
Alexander
а при чем тут validated?
Ignat
Alexander
а
Alexander
там же полугруппа нет, разве?
Alexander
Semigroup e => Semigroup (Validation e a)Source#
Monoid e => Monoid (Validation e a)Source
Ignat
ну да
Ignat
я контекст немножко упустил)))
Ignat
я просто не шарю, как называется Alternative без нейтрального элемента
Alexander
https://twitter.com/cartazio/status/973545338538745862?s=20 Carter is so Carter
Denis
в TH можно как-то посмотреть что есть в скоупе и если нет того что надо, то ругаться по особому?
Denis
норм, а можно при этом проверить что имя из нужного модуля импортировано?
Denis
ну или qualified требовать
Denis
ладно, проверю сам, спасибо
Cheese
да, lookupValueName "GHC.Base.Nothing"
Cheese
lookupValueName "Prelude.Nothing"
Cheese
можно пропустить лукап, если не нужна понятная ошибка
λ> ;$(do info <- reify $ mkName "()"; runIO $ print info; pure [])
TyConI (DataD [] GHC.Tuple.() [] Nothing [NormalC GHC.Tuple.() []] [])
λ> ;$(do info <- reify $ mkName "("; runIO $ print info; pure [])
<interactive>:18:4: error: ‘(’ is not in scope at a reify
кана
tagless final это все таки очень удобно
кана
Императивную бизнес-логику зачастую хочется абстрагировать от всего и иметь ограниченный встроенный язычок для ее описания (edls), который можно по разному интерпретировать (замокать для тестов например), для этого в хаскеле есть несколько разных путей, в том числе free/freer-монады, tagless final pattern.
Представим простую задачу: мы пишем софт для некого банка и нужно описать сценарий проверки баланса всех юзеров. Нужно оповестить всех юзеров с нулевым балансом об их балансе.
Сам сценарий:
notifyUsersOnEmptyBalance = do
usersIds <- getUsersIds
for_ usersIds $ \userId -> do
balance <- getBalance userId
when (balance <= 0) $ do
sendEmail userId "Empty balance"
А в этом гисте я написал 3 рабочих (можете скопировать куда-нибудь и выполнить, никаких зависимостей не нужно) кода с реализацией этого. Внимание, на free/freer примерах есть и опредение самоих free/freer монад, в реальных проектах их обычного берут из библиотек, так что можно не учитывать их.
https://gist.github.com/kana-sama/6fc14ce18bc10303a36c047fbf36a043
Первые два варианта (free/freer) генерируют из сценария ленивый список команд (ленивый в том смысле, что каждая следующая команда генерируется после выполнения предыдущей и зависит от результата ее выполнения), который затем выполняется интерпретатором. Freer-версия куда удобнее в описании, а так же намного лучше по перфомансу нежели Free-версия.
Tagless final pattern версия самая короткая и удобная, но в ней мы не можем например приостановить выполнение сценария (и продолжить выполнять после).
Leonid 🦇
Мы можем сделать инстанс такой что он будет эти ваши фри генерировать
Denis
и выкидывать
Leonid 🦇
Можно писать в лог и делать золотые тесты
Leonid 🦇
Целый дождь таких тестов
Alexander
я немного не понял, а нафига все это?
Serghei
офтопик: как вы относитесь к версионированию build-артефактов? это когда зависимости не инсталируются при релизе, а берутся из архива. Именно те, которые инсталились в ту среду где было тестирование
кана
Alexander
да
Leonid 🦇
Alexander
ну то есть можно было бы точно так же сделать только с произведением типов вместо суммы?
кана
можно делать без этого и писать сразу такой код:
кана
кана
и все ок пока нам не захочется это протестировать
кана
мы не сможем поменять подменить реализацию для тестов и читать не из базы
кана
и ничего нас не ограничит в таком коде делать то что нельзя
кана
фри и тэглес финал:
- позволят подменять интерпретатор или реализацию
- ограничивают язык только тем, что можно в сценариях использовать
Alexander
ну давай сделаем так
data App = App {
GetUsersIds ::IO [UserId]
GetBalance :: UserId -> IO Balance
SendEmail :: UserId -> Email -> IO ()
}
Alexander
что мы теряем?
кана
да в принципе все
кана
как это вообще нам помогает что-то сделать)
Leonid 🦇
Чтение из базы в тестах это норма. Интеграционные тесты важнее юнит тестов. В оперденях юниттестить обычно нечего
Serghei
кана
кана
кана
ты просто меняешь тайпкласс на словарик
Leonid 🦇
Да ладно, га тестовой машине Сендмейл не настроен полюбасу....
Alexander
эй, это я спросил в чем отличие
Leonid 🦇
Словарик часто удобнее
Alexander
#ifdef TEST...
кана
вот это - это и есть твое решение со славарем
кана
только этот словарик будет пробрасываться неявно
Denis
кана
кана
сначала было просто про сумму и произведение
Alexander
в терминах типов
кана
еще раз
кана
можно пробросить сумму методов (без их выполнения, это что-то вроде адт) - это фри решение
кана
можно произведение - это тэглесс финал
кана
в моем посте оба случая есть
кана
сумма - первые два
произведение - последнее
Alexander
а вот это дислайк
ой да ладно тебе, это дислайк до тех пор пока случайно из тестового энва не отправишь письмо реальному клиенту :)
кана
про разницу между ними у меня тоже написано:
Первые два варианта (free/freer) генерируют из сценария ленивый список команд (ленивый в том смысле, что каждая следующая команда генерируется после выполнения предыдущей и зависит от результата ее выполнения), который затем выполняется интерпретатором. Freer-версия куда удобнее в описании, а так же намного лучше по перфомансу нежели Free-версия.
Tagless final pattern версия самая короткая и удобная, но в ней мы не можем например приостановить выполнение сценария (и продолжить выполнять после).
Alexander
Denis
Denis
CPP это дорога в ад
Alexander
ну я бы #ifdef TEST error "should be mocked in test env написал всетаки
Denis
еще хуже
Denis
еще и взорвется в тестовом режиме
Denis
это же просто вопрос того каким действием проинициализировать тестовое окружение
Denis
на входе программы вычитали окружение и конструируем подменяемые действия
Denis
как в примере выше с рекордом
Denis
вопрос того чем заполнить поля
Alexander
ну да
Alexander
ну вообще мне кажется пример для фримонад у @kana_sama выбран неудачно
кана
да классический пример вроде