Scala中函数值的提升方法

Scala中函数值的提升方法,scala,Scala,Scala库是否支持将给定类型的方法提升为函数值 例如,假设我想提升String.length。我会写字 val f: String => Int = _.length 或 但是,这种语法并不总是理想的(尤其是在较大表达式中)。我想我正在寻找一种可以实现如下表达式的东西 Lift[String](_.length) Lift[Option[Int]].lift(_.filter) 我的想法是这样的: class Lift[T] {

Scala库是否支持将给定类型的方法提升为函数值

例如,假设我想提升
String.length
。我会写字

val f: String => Int = _.length

但是,这种语法并不总是理想的(尤其是在较大表达式中)。我想我正在寻找一种可以实现如下表达式的东西

Lift[String](_.length)
Lift[Option[Int]].lift(_.filter)
我的想法是这样的:

class Lift[T] {                                                          
   def apply[R](f: T => R): T => R = f

   def lift[A, R](f: (T) => (A) => R): (T, A) => R = 
         f(_)(_) 
   def lift[A1, A2, R](f: (T) => (A1, A2) => R): (T, A1, A2) => R =
         f(_)(_,_)
   // ... etc. ...
}
object Lift {
   def apply[T] = new Lift[T]
}
问题1:标准库(或任何库)是否提供类似的功能

问题2:如果没有,是否可以这样编写:
Option.filter
可以像上面那样被提升(而不是像
Lift[Option[Int]]。Lift[Int=>Boolean,Option[Int]](_u.filter)
)?在未提供提升方法上的类型参数的情况下,我得到以下错误:

error: missing parameter type for expanded function ((x$1) => x$1.filter) Lift[Option[Int]].lift(_.filter) ^ 错误:缺少扩展函数的参数类型((x$1)=>x$1.filter) 提升[选项[Int]].Lift(u.filter) ^ 更新:


显然,我遇到的问题与重载的
lift
方法有关。如果我重命名重载,我可以取消
选项。filter
而不需要所有额外的类型参数。

将filter作为部分应用的方法传入似乎可以完成以下工作:

scala> class Lift[T] {                                        
     |    def apply[R](f: T => R): T => R = f
     | }
defined class Lift

scala> object Lift {
     |    def apply[T] = new Lift[T]
     | }
defined module Lift

scala> val ls = Lift[String](_.length)
ls: (String) => Int = <function1>

scala> val los = Lift[Option[Int]](_.filter _)     
los: (Option[Int]) => ((Int) => Boolean) => Option[Int] = <function1>
scala>类提升[T]{
|def应用[R](f:T=>R):T=>R=f
| }
限定级别提升
scala>对象提升{
|def应用[T]=新提升[T]
| }
限定模块提升
scala>val ls=Lift[String](.长度)
ls:(字符串)=>Int=
scala>val los=Lift[选项[Int]](u.filter)
服务水平:(选项[Int])=>((Int)=>布尔)=>选项[Int]=

有什么问题

(_: String).length
(_: Option[Int]).filter _

我终于想出了一个我满意的解决办法。这个版本支持简单的语法和API的单一入口点,同时还提供对提升函数形式的控制(即未转换、部分转换或完全转换)

示例

我将在下面的示例中使用以下类定义:

class Foo {
   def m1: Int = 1
   def m2(i: Int): Int = i
   def m3(i: Int, j: Int): Int = i + j
}
提升的最简单形式是将方法作为部分应用的函数返回,相当于调用
((:Foo).method\ux)


我以前的解决方案要求对每种类型采用单独的提升方法:

import Lift._
val f1 = lift0[String](_.length)
val f2 = lift1[Option[Int]](_.filter)
val f3 = lift2[Either[String, Int]](_.fold)
实施:

class Lift[T] {
   def apply[R,F](f: T => R)(implicit e: (T => R) Liftable F): F = e.lift(f)
}
object lift {
   def apply[T] = new Lift[T]
}

class Liftable[From, To](val lift: From => To)

class DefaultLiftables {
   implicit def lift[F]: F Liftable F = new Liftable(identity)
}
object Liftable extends DefaultLiftables

class UncurriedLiftable1 extends DefaultLiftables {
   implicit def lift1[T, A, R]: (T => A => R) Liftable ((T, A) => R) = 
      new Liftable( f => f(_)(_) )
}
class UncurriedLiftable2 extends UncurriedLiftable1 {
   implicit def lift2[T, A1, A2, R]: (T => (A1, A2) => R) Liftable ((T, A1, A2) => R) = 
      new Liftable ( f => f(_)(_,_) )
}
// UncurriedLiftable3, UncurriedLiftable4, ...
object UncurriedLiftables extends UncurriedLiftable2

class CurriedLiftable2 extends DefaultLiftables {
   implicit def lift2[T, A1, A2, R]: (T => (A1, A2) => R) Liftable (T => A1 => A2 => R) =
      new Liftable( f => (x: T) => (a1: A1) => (a2: A2) => f(x)(a1, a2) )
}
// CurriedLiftable3, CurriedLiftable4, ...
object CurriedLiftables extends CurriedLiftable2
class Lift0[T] {
   def apply[R](f: T => R): T => R = f
}
class Lift1[T] {
   def apply[A, R](f: (T) => (A) => R): (T, A) => R = 
      f(_)(_) 
}
class Lift2[T] {
   def apply[A1, A2, R](f: (T) => (A1, A2) => R): (T, A1, A2) => R =
      f(_)(_,_)
}
// ... etc. ...

object Lift {
   def lift0[T] = new Lift0[T]
   def lift1[T] = new Lift1[T]
   def lift2[T] = new Lift2[T]
   // ... etc. ...
}

这应该是(_:Option[Int]).filter(注意后面的下划线!)不错。我希望得到一个完全未编译的表单,但我可能不得不满足于此。我提出了一个解决方案,提供了一个语法至少像这样简单的提升函数,但它也让调用方控制提升函数的形式(curried、party curried或uncurried)。看看您是否感兴趣。@DanielC.Sobral,我如何在您的答案中阅读后一个函数的结果?在我的示例中,我将g()设置为等于它
scala>g(Some(3))res23:(Int=>Boolean)=>Option[Int]=
@Kevin它需要更多的参数列表。例如,
g(Some(3))(%2==0)
。这是可行的,但我希望得到一个
(Option[Int],(Int=>Boolean)=>Option[Int]
。我提出了一个解决方案,它提供了一个语法简单的提升函数,但也让调用方控制提升函数的形式(curried、party curried或uncarried)。看看你是否感兴趣。
class Lift[T] {
   def apply[R,F](f: T => R)(implicit e: (T => R) Liftable F): F = e.lift(f)
}
object lift {
   def apply[T] = new Lift[T]
}

class Liftable[From, To](val lift: From => To)

class DefaultLiftables {
   implicit def lift[F]: F Liftable F = new Liftable(identity)
}
object Liftable extends DefaultLiftables

class UncurriedLiftable1 extends DefaultLiftables {
   implicit def lift1[T, A, R]: (T => A => R) Liftable ((T, A) => R) = 
      new Liftable( f => f(_)(_) )
}
class UncurriedLiftable2 extends UncurriedLiftable1 {
   implicit def lift2[T, A1, A2, R]: (T => (A1, A2) => R) Liftable ((T, A1, A2) => R) = 
      new Liftable ( f => f(_)(_,_) )
}
// UncurriedLiftable3, UncurriedLiftable4, ...
object UncurriedLiftables extends UncurriedLiftable2

class CurriedLiftable2 extends DefaultLiftables {
   implicit def lift2[T, A1, A2, R]: (T => (A1, A2) => R) Liftable (T => A1 => A2 => R) =
      new Liftable( f => (x: T) => (a1: A1) => (a2: A2) => f(x)(a1, a2) )
}
// CurriedLiftable3, CurriedLiftable4, ...
object CurriedLiftables extends CurriedLiftable2
import Lift._
val f1 = lift0[String](_.length)
val f2 = lift1[Option[Int]](_.filter)
val f3 = lift2[Either[String, Int]](_.fold)
class Lift0[T] {
   def apply[R](f: T => R): T => R = f
}
class Lift1[T] {
   def apply[A, R](f: (T) => (A) => R): (T, A) => R = 
      f(_)(_) 
}
class Lift2[T] {
   def apply[A1, A2, R](f: (T) => (A1, A2) => R): (T, A1, A2) => R =
      f(_)(_,_)
}
// ... etc. ...

object Lift {
   def lift0[T] = new Lift0[T]
   def lift1[T] = new Lift1[T]
   def lift2[T] = new Lift2[T]
   // ... etc. ...
}