Size: a a a

Scala User Group

2020 May 14

Oℕ

Oleg ℕizhnik in Scala User Group
Aλeχander Semenov
Это часть большей проблемы, давай я лучше зайду с другой стороны, т.к. возможно подтупливаю. ) Контекст создается во время веб запроса, то есть при старте аппа его нету. Должен ли тогда быть тип контекста Option[Ctx] или каким-то ADT? Но тогда мне в веб ресурсе нужен F WithLocal Option[Ctx]. Это ок. Но сервис слою нужен F WithContext Ctx, как мне к нему прийти из F WithLocal Option[Ctx]?
Т.е. идея в том, что ты инициализируешь приложение в каком-то
RIO[SystemEnv, A] \  Task[A]\ IO[A]

А запускаешь в RIO[SystemEnv with AppEnv, A] \  Env[MyContext, A] \ ReaderT[IO, MyContext, A]
источник

Oℕ

Oleg ℕizhnik in Scala User Group
Aλeχander Semenov
Это часть большей проблемы, давай я лучше зайду с другой стороны, т.к. возможно подтупливаю. ) Контекст создается во время веб запроса, то есть при старте аппа его нету. Должен ли тогда быть тип контекста Option[Ctx] или каким-то ADT? Но тогда мне в веб ресурсе нужен F WithLocal Option[Ctx]. Это ок. Но сервис слою нужен F WithContext Ctx, как мне к нему прийти из F WithLocal Option[Ctx]?
Именно поэтому MakeRef, MakeMVar, Logs и т.п. позволяют тебе делать
I[Foo[F]]
где I - инициализирующий эффект, в котором контекста нет  RIO[SystemEnv, A] \  Task[A]\ IO[A]
а F - контекстный эффект, которому нужен контекст для работы RIO[SystemEnv with AppEnv, A] \  Env[MyContext, A] \ ReaderT[IO, MyContext, A]
источник

Oℕ

Oleg ℕizhnik in Scala User Group
Если говорить о значениях, которые определяются для каждого запроса отдельно, типа TraceId, StartTime, LocalLogs и т.п.
источник

Oℕ

Oleg ℕizhnik in Scala User Group
То да - ты можешь придумать какие-то пустые значения на старте, а потом модифицировать их
источник

Oℕ

Oleg ℕizhnik in Scala User Group
А можешь вообще не придумывать и инициализировать кусочек во время запуска очередного запроса.
Тогда может получиться, что у тебя есть два контекста, один шире другого
источник

Oℕ

Oleg ℕizhnik in Scala User Group
И для таких двух контекстов тоже можно получить Unlift
источник

Oℕ

Oleg ℕizhnik in Scala User Group
Unlift[F, G] обычно говорит, что G имеет больше информации, чем F в контексте, поэтому я могу получить либо F ~> G естественным образом, либо
G[G ~> F] т.е. собрать недостающую информацию из контекста, а потом дополнять ей каждый раз контекст из F для запуска контекста из G
источник

AS

Aλeχander Semenov in Scala User Group
Oleg ℕizhnik
А можешь вообще не придумывать и инициализировать кусочек во время запуска очередного запроса.
Тогда может получиться, что у тебя есть два контекста, один шире другого
пока что примерно так и есть, но тогда может получиться, что сервис может быть вызван с неполным контекстом, например при обработке сообщений из кафки или чего-то такого. А хочется, чтобы на уровне типов это было невозможно. Но видимо защититься от этого нельзя, например если у меня сервис имплистно в конструкторе получает F WithContext Ctx, и я в нем же начинаю слушать сообщения из кафки, то там можно обратиться к этом Ctx, который неполноценный. Можно конечно там натыкать опшнов или ADT, но это будет боль. Пока что есть специальный "системный" контекст, который используется при старте и в UnsafeExecFuture:

object System extends SecurityContextLike {

 override def correlationUuid: CorrelationUuid = fail("correlation id")
 override def user: UserLike = fail("user")
 override def company: CompanyLike = fail("company")

 private def fail(method: String): Nothing =
   throw new IllegalArgumentException(s"Cannot retrieve $method from system context")

}


Но это ненадежно.
источник

AS

Alex Sh in Scala User Group
Народ, привет.
Есть какая-нть либа для 2.12 + 2.13 которая умеет выводить функторы для такого:
final case class Calls[F[_], R] (
 call1: Int => F[Option[R]],
 call2: (String, Int) => F[List[R]],
 //...
 callN: Boolean => F[R]
)
Если такое делать ручками, то получается довольно много кода по перекладыванию функций в Kleisli и назад.
P.S. Подразумевается, что для F[_] тоже есть функтор
P.P.S Нужен Functor[Calls[F, *]]
источник

Oℕ

Oleg ℕizhnik in Scala User Group
а почему трейтом не сделать
источник

Oℕ

Oleg ℕizhnik in Scala User Group
зачем кейскласс функций
источник

AS

Alex Sh in Scala User Group
Oleg ℕizhnik
а почему трейтом не сделать
А для трейтов есть такое?
источник

Oℕ

Oleg ℕizhnik in Scala User Group
да
источник

Oℕ

Oleg ℕizhnik in Scala User Group
источник

Oℕ

Oleg ℕizhnik in Scala User Group
или @derive(functor)
источник

AS

Alex Sh in Scala User Group
Oleg ℕizhnik
зачем кейскласс функций
штоб мокать в тестах удобнее было

fakeCalls.copy(call1 = mockedCall1)
источник

Oℕ

Oleg ℕizhnik in Scala User Group
cats-tagless \ derevo-cats-tagless
источник

AS

Alex Sh in Scala User Group
Oleg ℕizhnik
cats-tagless \ derevo-cats-tagless
В таглесс видел вывод только для FunctorK, но ок, еще раз гляну
источник

Oℕ

Oleg ℕizhnik in Scala User Group
Там есть для функтора
источник

Oℕ

Oleg ℕizhnik in Scala User Group
Но если даже у тебя было только для функторК, всё равно выразить можно было бы
источник