Coder Social home page Coder Social logo

tofu-tf / tofu Goto Github PK

View Code? Open in Web Editor NEW
526.0 526.0 89.0 20.95 MB

Functional programming toolbox

Home Page: https://tofu-tf.github.io/tofu/

License: Apache License 2.0

Scala 98.67% Dockerfile 0.01% JavaScript 0.99% CSS 0.32%
concurrent config effects functional-programming hacktoberfest logging optics reader-monad tagless-final typeclasses

tofu's People

Contributors

catostrophe avatar d1skort avatar danslapman avatar dependabot[bot] avatar dos65 avatar evo-funfunfine avatar funfunfine avatar geny200 avatar grryum avatar gurinderu avatar gusevtimofey avatar klimovsv avatar mehakun avatar mergify[bot] avatar odomontois avatar optician avatar oskin1 avatar pomadchin avatar road21 avatar roman-statsura avatar scala-steward avatar sigevsky avatar ssstlis avatar susliko avatar terjokhin avatar tofu-bot avatar vagroz avatar valery-shinkevich avatar vilunov avatar z1kkurat avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tofu's Issues

Add convenient syntax for working with F[Option[A]]

We interested in few handy methods, that would allow to do basic things with F[Option[A]] with additional context Monad[F] without wrapping it inOptionT
possible list is

def getOrElseF(fa: => F[A]): F[A]
def orElseF(fa: => F[Option[A]]): F[Option[A]]
def orThrow(err: => E)(implicit FE: Raise[F, E]): F[A]
def flatMapOpt[B](f: A => F[B]): F[Option[B]]
def doubleFlatMap[B](f: A => F[Option[B]]): F[Option[B]]

Daemon.exit hangs in some cases

The exit methon can hang forever if the daemon is canceled immediately after it is created. The following code throws a TimeoutException, in my case on the second or third iteration: https://scastie.scala-lang.org/ZEIyjIhUQjORqtfSpAf6Yg. No exception is thrown if:

  • the call to cancel is removed
  • the call to exit is removed
  • or some delay is added between the calls to daemonize and cancel.

I think the problem is with this line: https://github.com/TinkoffCreditSystems/tofu/blob/master/concurrent/src/main/scala/tofu/concurrent/Daemon.scala#L38. The underlying fiber can be canceled before it even starts, so the block inside the guaranteeCase will not be executed and the Deferred will not be completed with a value.

Logging with Marker

Apparently, while trying to log values with additional marker using logging provided by Logs.sync, we encounter java.lang.StackOverflowError

Code example:

  case class User(name: String, age: Int)
  object User{
    implicit val userShow: Show[User] = user => s"name=${user.name}, age=${user.age}"

    implicit val userLoggable: Loggable[User] = Loggable.show[User]
  }

  val testUser = User("John", 42)
  val marker = MarkerFactory.getMarker("some.marker")

  class MyService[F[_]: Logging: Monad] {
    def doLogging(): F[Unit] =
      for {
//         works
        _ <- Logging[F].info(s"User: ${testUser.show}", testUser)  
//         doesn't work
        _ <- Logging[F].infoWithMarker(s"User: ${testUser.show}", marker, testUser)
      } yield ()
  }

  object MyService {
    def apply[I[_]: Functor, F[_]: Monad](implicit logs: Logs[I, F]): I[MyService[F]] = {
      logs.forService[MyService[F]].map(implicit l => new MyService[F])
    }
  }

  implicit val logs: Logs[IO, IO] = Logs.sync[IO, IO]

  val io: IO[Unit] = for {
    service <- MyService[IO, IO]
    _       <- service.doLogging()
  } yield ()

  io.unsafeRunSync()
}

Result:

Exception in thread "main" java.lang.StackOverflowError
at tofu.logging.impl.LoggingImpl.writeMarker(LoggingImpl.scala:26)
at tofu.logging.LoggingBase.infoWithMarker(Logging.scala:49)
at tofu.logging.LoggingBase.infoWithMarker$(Logging.scala:48)
at tofu.logging.impl.LoggingImpl.infoWithMarker(LoggingImpl.scala:8)
at tofu.logging.impl.LoggingImpl.writeMarker(LoggingImpl.scala:29)
at tofu.logging.LoggingBase.infoWithMarker(Logging.scala:49)
at tofu.logging.LoggingBase.infoWithMarker$(Logging.scala:48)
at tofu.logging.impl.LoggingImpl.infoWithMarker(LoggingImpl.scala:8)

I believe the problem is with tofu.logging.impl.SyncLogging. There are no overriding of traceWithMarker, infoWithMarker... methods.

Derive `Embed` instance for non-representable traits

Right now Embed is derived only as subtype of RepresentableK

But having trait such as

def Foo[F]{
   def foo(input: F[Int]): F[String]
}

it is still possible to derive an instance of Embed as follows

implicit val fooEmbed: Embed[Foo] = new Embed[Foo]{
    final def embed[F[_]: FlatMap](ffoo: F[Foo[F]]) = new Foo[F]{
        def foo(input: F[Int]) = ffoo.flatMap(_.foo(input))
   }
}

Bifunctor alternative for Env?

Separate type for typed error (not fixed to Throwable) can be useful in many situations, including expressing absence of error (as Nothing) as well as representing some domain errors.
Monix contributors are already working on BIO alternative to Task (https://github.com/monix/monix-bio).
Should we provide such an alternative to Env? Probably it would be wiser to build it upon Monix BIO implementation (or not).

Inconsistency in tofu.syntax.handle

Having some Handle[F, E], I can handle errors of type E1 <: E with the handleWith method, but not with handle: https://scastie.scala-lang.org/jzaAE02dRwuYlnD7nLaQ7Q

This is because the handleWith method requires Handle[F, E1], which can be derived from Handle[F, E] using handleDowncast. But the handle method requires HandleTo[F, F, E1], which can not be derived.

I think the easiest way to fix this is to require Handle[F, E] in the handle method. But I don't know if there might be cases where HandleTo[F, F, E] is available, but Handle[F, E] is not.

Logging-refined module

Hi
I day-by-day using tofu i found out that i need to manually create a snippet with implicit conversion to support loggable instances for refined types.
I would like to create PR if you don't mind =)

ContextShift instance for ContextT

Request for ContextShift instance for ContextT; tried to implement myself:

 implicit def ContextTContextShift[F[+_], C[_[_]]](implicit cs: ContextShift[F]): ContextShift[ContextT[F, C, *]] = new ContextShift[ContextT[F, C, *]] {
    def shift: ContextT[F, C, Unit] = ContextT.lift(cs.shift)
    def evalOn[A](ec: ExecutionContext)(fa: ContextT[F, C, A]): ContextT[F, C, A] = ContextT.provideF(ctx => cs.evalOn(ec)(fa.run(ctx)))
  }

Tofu philosophy

At this point tofu states to be a set of functional recipies.

I think, we should establish a more specific philosophy, emphasize the certain problems, which tofu is aimed to solve.
A clearly defined set of use-cases would help to answer the "Why do I need tofu?" question and to determine the direction of future development.

Refine tofu.syntax.context

  1. It would be nice to have
def askF[F[_]] = ...

similarly to ask syntax.

  1. Also context might have the following variant:
def context[F[_], C](implicit ctx: HasContext[F, C]): F[C] = ctx.context

to distinguish among several Context[F] instances in the scope

Documentation roadmap

The goal of this issue is to track an overall progress over tofu documentation.
I propose the following structure:

Core

  • Error management (split into Raise, Handle/Restore pages?)
  • Forking and racing (split into Fire, Race, Start pages?)
  • Execute
  • Guarantee
  • Timeout
  • Void

Contextual

  • Env
  • Context (rename page from HasContext to Context?)

Concurrent

  • Agent
  • Atom
  • Daemon
  • GateKeeper
  • ReadWrite
  • QVar
  • MakeDeferred
  • MakeMVar
  • MakeRef
  • MakeSemaphore

Optics

  • Hierarchy
  • Contains
  • Equivalent
  • Extract
  • Folded
  • Items
  • Property
  • Subset
  • Updated

Utilities

  • Config
  • Console
  • Logging
  • Memo

Any comments are highly appreciated!

Implement functions for Option\Either

We need something like

def some[A]: Subset[Option[A], A]
def none[A]: Subset[Option[A], Unit]
def left[A, B]: Subset[Either[A, B], A]
def right[A, B]: Subset[Either[A, B], B]

in the tofu.optics.functions

Add docs for logging module

I’m quite annoyed by constant complaining in Scala Group about tofu documentation. Let’s change that, starting from logging.

Support covariance in syntax

i.e. for all syntax methods such as:

def flatTap[B](f: C => F[B])(implicit F: FlatMap[F]): F[C] = F.flatTap(fa)(f)

Replace with:

def flatTap[G[x] >: F[x], B](f: C => G[B])(implicit G: FlatMap[G]): G[C] = G.flatTap(fa)(f)

Motivation? The following works with covariant syntax:

Some(1).flatTap(_ => None)

But doesn't work with naive LEGACY syntax encodings.

Implement Agent

Implement new concurrent datatype Agent mostly like RefM from ZIO and looking like Ref + Semaphore (Atom + Gatekeeper) for everything else

It should have at least following methods

trait Agent[F[_], A]{
  // return current value, this will never block
  def get: F[A]
  // update value with effectful transformation, wait for the new result
  def updateM(f: A => F[A]): F[A]
  // enqueue transformation, return immediately
  def fireUpdateM(f: A => F[A]): F[Unit]
  // modify value with effectful transformation, wait for the new result
  def modifyM[B](f: A => F[(A, B)]): F[B]
}

Fix TofuBracketMVarOps.bracketUpdate

Current method is nonsense, we should transform it to a method, accepting A => F[A] and putting result on success,

Behavior should be related to datatype described in #95

Ambiguous implicit values of Fire for Env

Using Fire with Env fails due to ambiguous implicit instances, that come from EnvInstances and StartInstances.

import cats._
import cats.syntax.applicative._

import tofu._
import tofu.env._

type MyEnv[A] = Env[Unit, A]
object MyEnv extends EnvSpecializedFunctions[Unit]

def f[F[_]: Fire: Applicative]: F[Unit] = Applicative[F].unit

f[MyEnv]

This results in

ambiguous implicit values:
 both method envInstance in trait EnvInstances of type [E]=> tofu.env.EnvFunctorstance[E]
 and method concurrentInstance in trait StartInstances of type [F[_]](implicit F: cats.effect.Concurrent[F])tofu.Fire[F]
 match expected type tofu.Fire[Playground.MyEnv]

https://scastie.scala-lang.org/9UKp4m7ZRN23ydHGetWLzA

Make docs

Write and publish nice docs using mdoc/microsite

LogginImpl stackoverflow

import cats.effect.IO
import org.slf4j.LoggerFactory
import tofu.logging.Logging
import tofu.logging.impl.LoggingImpl

object HerdingAnimals {
  def main(args: Array[String]): Unit = {
    implicit val logger: Logging[IO] = new LoggingImpl[IO](LoggerFactory.getLogger(getClass.getName)) {}
    logger.info("test").unsafeRunSync()
  }
}

Runtime:

Exception in thread "main" java.lang.StackOverflowError
	at tofu.logging.impl.LoggingImpl.write(LoggingImpl.scala:17)
	at tofu.logging.LoggingBase.info(Logging.scala:41)
	at tofu.logging.LoggingBase.info$(Logging.scala:41)
	at tofu.logging.impl.LoggingImpl.info(LoggingImpl.scala:8)
	at tofu.logging.impl.LoggingImpl.write(LoggingImpl.scala:20)
	at tofu.logging.LoggingBase.info(Logging.scala:41)
	at tofu.logging.LoggingBase.info$(Logging.scala:41)
	at tofu.logging.impl.LoggingImpl.info(LoggingImpl.scala:8)
	at tofu.logging.impl.LoggingImpl.write(LoggingImpl.scala:20)
	at tofu.logging.LoggingBase.info(Logging.scala:41)
	at tofu.logging.LoggingBase.info$(Logging.scala:41)

Consider changing scalafmt rules

I do support the need for a forced formatter in a project with many contributors, but the current ruleset is awful and doesn't work properly in IDEA (has some wrong fields).

Incorrect EmbedLogging implementation

EmbedLogging passes all parameters into the underlying implementation as a a single array.

object Demo extends App {
  val zioLogs = ZLogs.uio.byName("demo")

  implicit val logs = Embed[Logging].embed(zioLogs)

  def run(args: List[String]) = info"${1} ${2} ${3}".as(0)
}

The code above outputs [1,2,3] {} {} instead of 1 2 3. I think the problem is in the write method:

def write(level: Logging.Level, message: String, values: LoggedValue*): F[Unit] =
  underlying.flatMap(_.write(level, message, values))

Should be

underlying.flatMap(_.write(level, message, values: _*))

Sentry integration with logging

It is nice to have some way to integrate sentry with tofu logging, but I couldn't find any ways to do it. Is there any?
If not, how can I help to implement this?

Logging-shapeless module

Hi
I day-by-day using tofu i found out that i need to manually create a snippet with implicit conversion to support loggable instances for tagged types.
I would like to create PR if you don't mind =)
(sorry for copy-pasting)

Add convenient syntax for working with F[Either[E, A]]

We interested in few handy methods, that would allow to do basic things with F[Either[E, A]] with additional context Monad[F] without wrapping it in EitherT
possible list is

def orElse(f: => F[Either[E, A]]): F[Either[E, A]]
def catchAll(e: E => F[A]): F[A]
def absolve(implicit R: Raise[F, E]): F[A]
def flatMapR[B](f: A => F[B]): F[Either[E, B]]
def flatMapL[E](f: E => F[E1]): F[Either[E1, A]]
def doubleFlatMap[B](f: A => F[Either[E, B]]): F[Either[E, B]]

Create front page

Create a front page in this repo or another with main information about repo, probably some blog to bee seen at tofu.tf

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.