假设我有一组规则,其中有一个IO[Boolean]在运行时返回的验证函数。
case class Rule1() {
def validate(): IO[Boolean] = IO.pure(false)
}
case class Rule2() {
def validate(): IO[Boolean] = IO.pure(false)
}
case class Rule3() {
def validate(): IO[Boolean] = IO.pure(true)
}
val rules = List(Rule1(), Rule2(), Rule3())
Run Code Online (Sandbox Code Playgroud)
现在我必须迭代这些规则并查看“这些规则中的任何一个是否有效”,如果不有效则抛出异常!
for {
i <- rules.map(_.validate()).sequence
_ <- if (i.contains(true)) IO.unit else IO.raiseError(new RuntimeException("Failed"))
} yield ()
Run Code Online (Sandbox Code Playgroud)
上面代码片段的问题在于它试图评估所有规则!我真正想要的是在第一次验证时退出true。
不知道如何在 Scala 中使用猫效果来实现这一点。
我有一系列的错误或观点(Seq[Xor[Error,View]])
我想将此映射到第一个错误的Xor(如果有)或视图序列(Xor[Error, Seq[View]])或可能只是(Xor[Seq[Error],Seq[View])
我怎样才能做到这一点?
在haskell中,我可以对字符串执行以下操作
let f = sequence [id, reverse]
f "test"
Run Code Online (Sandbox Code Playgroud)
如果使用Cats更好的方法来解决这个问题,我有点不知所措.我现在有类似的东西
val f = List(fun1,fun2)
val data = "test"
f map {fun => fun(data)}
Run Code Online (Sandbox Code Playgroud)
是否可以使用Cats实现Sequence或SequenceU的实现?
前段时间我开始使用Cats,发现在大多数情况下使用它OptionT非常有用Future[Option[T]].但我面临一个缺点,使用AplicativeError我需要type FutureOption[T] = OptionT[Future, X]为匹配F[_]所需的类型定义类型别名,AplicativeError并明确指定我的表达式的类型FutureOption[T].
type FutureOption[T] = OptionT[Future, T] // definition to match F[_] kind
val x = OptionT.liftF(Future.failed(new Exception("error"))) : FutureOption[String] // need to specify type explicitly
x.recover {
case NonFatal(e) => "fixed"
}
Run Code Online (Sandbox Code Playgroud)
如果我删除了我的表达式的类型定义和显式类型规范,那么recover因为OptionT[Future, T]不匹配将无法使用F[_],因此无法将其隐式转换为AplicativeErrorOps.
不幸的是,下面的例子不起作用,因为没有recover方法.
val x = OptionT.liftF(Future.failed(new Exception("error")))
x.recover {
case NonFatal(e) => "fixed"
}
Run Code Online (Sandbox Code Playgroud)
有没有办法避免这种样板代码?至少我想避免明确指定表达式类型FutureOption[T].
假设我需要压缩三个列表来获取三元组列表.我可以这样写:
import cats._
import cats.data._
import cats.implicits._
(List(1, 2) |@| List(3, 4) |@| List(5, 6)) map {case (a, b, c) => (a, b, c)}
res1: List[(Int, Int, Int)] = List((1,3,5), (1,3,6), (1,4,5), (1,4,6), (2,3,5), (2,3,6), (2,4,5), (2,4,6))
Run Code Online (Sandbox Code Playgroud)
你能简化一下吗?
我有一个像这样的字符串到IO的映射Map[String, IO[String]],我想将其转换为IO[Map[String, String]].怎么做?
这是一个简单的服务示例,其方法返回reader:
trait Service1_1{
def s1f1:Reader[Map[String,Int],Int] =
Reader(_("name"))
def s1f2:Reader[Map[String,Int],Int] =
Reader(_("age"))
}
Run Code Online (Sandbox Code Playgroud)
这是一个服务使用者,它接受参数,映射并返回读取器本身:
trait Service1_2 {
def s12f1(i:Int, map:Map[String,Int]):Reader[Service1_1, Int] =
Reader(s => {
val r = for {
r1 <- s.s1f1
r2 <- s.s1f2
} yield r1 + r2
r.run(map) + i
})
}
Run Code Online (Sandbox Code Playgroud)
好的,要使用Service1_2.s12f1,我必须在参数列表中具有map:
object s1 extends Service1_1
object s2 extends Service1_2
val r = s2.s12f1(3, Map("age"-> 1, "name"-> 2)).run(s1)
Run Code Online (Sandbox Code Playgroud)
问题:如何实施Service1_2.s12f2:
trait Service1_2 {
def s2f2 = ???
}
Run Code Online (Sandbox Code Playgroud)
为了能够像这样运行它:
s2.s2f2(2)
.run(s1)
.run(Map("age"-> 1, "name"-> 2)) …Run Code Online (Sandbox Code Playgroud) dependency-injection scala composition reader-monad scala-cats
使用cats.Semigroup可以这样写:
import cats.Semigroup
import cats.implicits._
val l1: String Either Int = Left("error")
val r1: String Either Int = Right(1)
val r2: String Either Int = Right(2)
l1 |+| r1 // Left("error")
r1 |+| r2 // Right(3)
Run Code Online (Sandbox Code Playgroud)
我希望有一个同样惯用的运算符(类似combine),其工作方式如下:
Right我的计算中至少有一个,则返回一个RightLeft,则返回一个Left例如:
Right(1) |+| Right(2) // Right(3)
Right(1) |+| Left("2") // Right(1)
Left("1") |+| Left("2") // Left("12") // in my particular case the wrapped value here does not really matter (could also be …Run Code Online (Sandbox Code Playgroud) 给定一个图,我需要生成所有拓扑顺序。例如,给定下图:
我想生成所有拓扑顺序,这些顺序是:
因为可能存在许多拓扑顺序,所以我需要延迟生成它们。当前,我有一个递归工作的实现,并且可以在scala-graph库的顶部进行工作:
import scalax.collection.Graph
import scalax.collection.GraphPredef._
import scalax.collection.GraphEdge._
import scala.collection.mutable.ArrayStack
import scala.collection.Set
def allTopologicalSorts[T](graph: Graph[T, DiEdge]): Stream[List[graph.NodeT]] = {
val indegree: Map[graph.NodeT, Int] = graph.nodes.map(node => (node, node.inDegree)).toMap
def isSource(node: graph.NodeT): Boolean = indegree.get(node).get == 0
def getSources(): Set[graph.NodeT] = graph.nodes.filter(node => isSource(node))
def processSources(sources: Set[graph.NodeT], indegrees: Map[graph.NodeT, Int], topOrder: List[graph.NodeT], cnt: Int): Stream[List[graph.NodeT]] = {
if (sources.nonEmpty) {
// `sources` contain all …Run Code Online (Sandbox Code Playgroud) 我在haskell的书中看到了一个示例,其中创建了一个简单的堆栈(推送,弹出),并在他们使用.put(..)或.pop()更新堆栈时始终返回monad状态。
提醒一下,该示例类似于以下内容:
pop :: State Stack Int
pop = State $ \(x:xs) -> (x,xs)
push :: Int -> State Stack ()
push a = State $ \xs -> ((),a:xs)
Run Code Online (Sandbox Code Playgroud)
这是有道理的,但是在看到此示例后,我开始怀疑我的域实体(比如说客户)。现在,我只是在每次要更新它(例如年龄)的东西时,都使用.copy()返回一个新的updated-Customer,就像许多文档中指出的那样,而不使用任何State monad。我使用.copy()的方式没有什么特别的:
case class Customer(age: Int, name: String) {
def updateAge(newAge: Int): Customer = {
this.copy(age = newAge)
}
}
Run Code Online (Sandbox Code Playgroud)
但是,我渴望看到的是,我不仅要返回更新后的副本,还必须返回State Monad,但是到目前为止,我还没有看到任何这样的示例(我自己学习),因此我感到困惑。我的印象是,有时会使用.copy(),而在其他不同情况下会使用State Monad,但是两者都管理State .....
每当我更新客户年龄时,是否应该退回State Monad?
scala ×10
scala-cats ×10
cats-effect ×1
composition ×1
exists ×1
findfirst ×1
graph ×1
haskell ×1
io ×1
io-monad ×1
reader-monad ×1
scalaz ×1
semigroup ×1