使用模式匹配计算的scala';s防护罩(如果)在体内

使用模式匹配计算的scala';s防护罩(如果)在体内,scala,pattern-matching,Scala,Pattern Matching,我经常在scala中使用模式匹配。很多时候,我需要做一些计算的一部分,有时他们是相当昂贵的。有没有办法将计算值绑定到单独的值 //我不想在体内安全使用prettyExpensiveFunc的结果 人。收集{ 案例 如果prettyExpensiveFunc(x,y)>0=>prettyExpensiveFunc(x),则某些情况(右((x,y))) } //理想情况下,类似的内容可能会有所帮助,但不会编译: 人。收集{ 案例 如果{valz=prettyExpensiveFunc(x,y);y>

我经常在scala中使用模式匹配。很多时候,我需要做一些计算的一部分,有时他们是相当昂贵的。有没有办法将计算值绑定到单独的值

//我不想在体内安全使用prettyExpensiveFunc的结果
人。收集{
案例
如果prettyExpensiveFunc(x,y)>0=>prettyExpensiveFunc(x),则某些情况(右((x,y)))
}
//理想情况下,类似的内容可能会有所帮助,但不会编译:
人。收集{
案例
如果{valz=prettyExpensiveFunc(x,y);y>0}=>z,则为某些情况(右((x,y))
}
//这种解决方案是有效的,但对于某些'Seq'类型来说并不安全,而且在使用更多案例时会有风险。
变量缓存:Int=0
人。收集{
案例
如果{cache=prettyExpensiveFunc(x,y);cache>0}=>cache
}
有没有更好的解决办法?
ps:这个例子很简单,我不希望有人会说我不需要模式匹配

为什么不先为每个元素运行函数,然后使用元组呢

Seq(1,2,3,4,5).map(e => (e, prettyExpensiveFunc(e))).collect {
  case ...
  case (x, y) if y => y
}

您可以使用
cats.Eval
使昂贵的计算变得懒惰和可记忆,使用
.map
创建
Eval
并在
中提取
.value
(如果需要,最多计算一次)。收集

values.map { value =>
  val expensiveCheck1 = Eval.later { prettyExpensiveFunc(value) }
  val expensiveCheck2 = Eval.later { anotherExpensiveFunc(value) }
  (value, expensiveCheck1, expensiveCheck2)
}.collect {
  case (value, lazyResult1, _) if lazyResult1.value > 0 => ...
  case (value, _, lazyResult2) if lazyResult2.value > 0 => ...
  case (value, lazyResult1, lazyResult2) if lazyResult1.value > lazyResult2.value => ...
  ...
}
如果不创建一些惰性评估的实现,我看不到一种做你想做的事情的方法,如果你必须使用一个,你最好使用现有的一个,而不是自己滚动一个

编辑。以防万一,您没有注意到-在此处使用元组不会丢失模式匹配的功能:

values.map {
  // originial value -> lazily evaluated memoized expensive calculation
  case a @ Some(Right((x, y)) => a -> Some(Eval.later(prettyExpensiveFunc(x, y)))
  case a                      => a -> None
}.collect {
  // match type and calculation
  ...
  case (Some(Right((x, y))), Some(lazyResult)) if lazyResult.value > 0 => ...
  ...
}

我试过自己的匹配器,效果还可以,但并不完美。我的matcher是非类型化的,而且让它完全类型化有点难看

类匹配器[T,E](f:PartialFunction[T,E]){
def unapply(z:T):选项[E]=if(f.isDefinedAt(z))Some(f(z))else None
}
def newMatcherAny[E](f:PartialFunction[Any,E])=新匹配器(f)
def newMatcher[T,E](f:PartialFunction[T,E])=新匹配器(f)
def prettyExpensiveFunc(x:Int)={println(s”--prettyExpensiveFunc($x)”;x%2+x*x}
val x=Seq(
有的(右(22)),,
有的(右(十)),,
有些(左(“哦现在”),
没有一个
)
val PersonAgeRank=newMatcherAny{case Some(Right(x:Int))=>(x,prettyExpensiveFunc(x))}
x、 收集{
如果排名>100=>println(“年龄:+age+”排名:+rank),则案例人物链接(年龄,排名)
}

因为它可能是许多案例子句中的一个,并且应该只对其中一些进行计算。如果不是
Int
而是
选项[Person,List[String]]]
则会更加困难,然后添加另一个
match
层以检查是否需要计算值。由于
PartialFunction
的原因,我无法执行。我不想匹配谓词不满足的情况。
如果
需要谓词,则返回
布尔值
。当
匹配时,如果
匹配,则知道它是
真的
。如果您必须重用该谓词,或者您从不同的值中获取参数,因此无法缓存它,或者您正在重用值,这意味着您可以在嵌套的
match
es和
If
s中对事物进行分组。。。正确的。重点是我很少期望布尔值。。。问题更新为使用int。我不需要不同的值来计算
prettyExpensiveFunc
,嵌套的
match
可以工作,如果我还将使用与谓词不匹配的值。。。就我而言,我将离开他们
收集
需要
部分功能
我真的需要有警卫,我真的很理解这个问题被否决的原因。是的。。。但你失去了与价值匹配的模式。。。在您的示例中,您使用
值计算,而不是提取值。很好。。。但这并不能简化任何事情。你所需要的只是简单地说是不可能的。不能在匹配项之间分配和传递值。每个匹配都是独立的纯计算,不打算在案例之间共享状态。您想要计算共享状态-您在模式匹配之外进行计算,例如,在ot之前。其他任何东西都是为了达到任意定义的优雅,而不给任何实际的好处。。。我不需要在比赛之间传球。。。我希望做的是将名称绑定到
if
=>
之后的case body中。没有简单的方法可以做到这一点,您的解决方案可以在类似的情况下使用。非常感谢您的时间。据我所知,您的解决方案不起作用-
prettyExpensiveFunction
的计算次数是每个值检查的次数的两倍。是的。。。你是对的。它做了我在开始时尝试做的事情(它需要被提取一次,并且它的工作原理类似于case with cache from question)。您的解决方案将正确缓存值,但代码更加冗长。我想没有完美的解决办法。