Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 如何正确使用IO和OptionT在服务层中进行理解?_Scala_Functional Programming_Scala Cats - Fatal编程技术网

Scala 如何正确使用IO和OptionT在服务层中进行理解?

Scala 如何正确使用IO和OptionT在服务层中进行理解?,scala,functional-programming,scala-cats,Scala,Functional Programming,Scala Cats,我有一个带有CRUD操作的简单存储库接口(可能,在general trait中将隐式会话作为参数传递是个坏主意): 我想这样使用它: for { _ <- repository.insert(???) _ <- repository.delete(???) v <- repository.find(???).value _ <- someFunctionReliesOnReturnedValue(v) } yield (???) 表: create ta

我有一个带有CRUD操作的简单存储库接口(可能,在general trait中将隐式会话作为参数传递是个坏主意):

我想这样使用它:

for {
  _ <- repository.insert(???)
  _ <- repository.delete(???)
  v <- repository.find(???).value
  _ <- someFunctionReliesOnReturnedValue(v)
} yield (???)
表:

create table entity (id numeric(38), value varchar(255));
我得到了编译错误:

错误:(69,13)类型不匹配;发现:cats.effect.IO[单位] 必需:cats.data.option[猫效应IO,?]
_一般来说,您应该将所有不同的结果转换为具有monad的“最通用”类型。在这种情况下,这意味着您应该在整个过程中使用
OptionT[IO,A]
,通过
OptionT.liftF将所有这些
IO[Entity]
转换为
OptionT[IO,Entity]

for {
  _ <- OptionT.liftF(repository.insert(???))
  _ <- OptionT.liftF(repository.delete(???))
  v <- repository.find(???)
  _ <- someFunctionReliesOnReturnedValue(v)
} yield (???)

有。此外,有些人更愿意返回
IO[Option[Entity]]
,并将其包装到
Option
中,仅在
中进行理解。你能不能把这个问题转换成一个更类似的格式?哦,当然,我会转换的。只是想展示一下基本的想法,你可以在yield中使用Util.createFile(e.value)。或者,使用=Util.createFile(e.value)而不是@LalitPrakash,问题是在这一步之后可能还有另一步,这取决于文件创建的结果(即使存在单位返回类型-这只是一个示例),谢谢您的回答!我知道主要意思,但我有几个问题。将不同的结果类型显式转换为最通用的类型是正确的方法吗?还是使用隐式转换更好?和我在示例中所做的一样,将不同的结果类型混合在一个单独的结果类型中以便于理解,这是“确定”的吗?FP方法对我来说是新的,所以我试图找出“最佳实践”,是否使用隐式转换取决于您的偏好。我认为社区的趋势是非常少地使用它们,因为它们往往违反了最小惊讶的原则。混合不同的一元类型(IO、OptionT、Future等)是行不通的,但混合它们包含的结果类型(Entity、Int等)也可以。
import java.nio.file.{Files, Paths}

import cats.data.OptionT
import cats.effect.IO
import scalikejdbc._

import scala.util.Try

case class Entity(id: Long, value: String)

object Entity extends SQLSyntaxSupport[Entity] {
  override def tableName: String = "entity"

  override def columnNames: Seq[String] = Seq("id", "value")

  def apply(g: SyntaxProvider[Entity])(rs: WrappedResultSet): Entity = apply(g.resultName)(rs)

  def apply(r: ResultName[Entity])(rs: WrappedResultSet): Entity =
    Entity(rs.long(r.id), rs.string(r.value))
}

trait Repository[Entity, PK] {
  def find(pk: PK)(implicit session: DBSession): OptionT[IO, Entity]

  def insert(e: Entity)(implicit session: DBSession): IO[Entity]
}

class EntityRepository extends Repository[Entity, Long] {
  private val alias = Entity.syntax("entity")

  override def find(pk: Long)(implicit session: DBSession): OptionT[IO, Entity] = OptionT{
    IO{
      withSQL {
        select(alias.resultAll).from(Entity as alias).where.eq(Entity.column.id, pk)
      }.map(Entity(alias.resultName)(_)).single().apply()
    }
  }

  override def insert(e: Entity)(implicit session: DBSession): IO[Entity] = IO{
    withSQL {
      insertInto(Entity).namedValues(
        Entity.column.id -> e.id,
        Entity.column.value -> e.value,
      )
    }.update().apply()
    e
  }
}

object EntityRepository {
  def apply(): EntityRepository = new EntityRepository()
}

object Util {
  def createFile(value: String): IO[Unit] = IO(Files.createDirectory(Paths.get("path", value)))
}

class Service {
  val repository = EntityRepository()

  def logic(): Either[Throwable, Unit] = Try {
    DB localTx {
      implicit session => {
        val result: IO[Unit] = for {
          _ <- repository.insert(Entity(1, "1"))
          _ <- repository.insert(Entity(2, "2"))
          e <- repository.find(3)
          _ <- Util.createFile(e.value) // error
          //after this step there is possible more steps (another insert or find)
        } yield ()
        result.unsafeRunSync()
      }
    }
  }.toEither
}

object Test extends App {
  ConnectionPool.singleton("jdbc:postgresql://localhost:5433/postgres", "postgres", "")
  val service = new Service()
  service.logic()
}
create table entity (id numeric(38), value varchar(255));
for {
  _ <- OptionT.liftF(repository.insert(???))
  _ <- OptionT.liftF(repository.delete(???))
  v <- repository.find(???)
  _ <- someFunctionReliesOnReturnedValue(v)
} yield (???)
val result: OptionT[IO, ...] = ...
result.value.unsafeRunSync().getOrElse(throw new FooException(...))