在 Scala 中提升函数值的方法

编程入门 行业动态 更新时间:2024-10-10 17:31:44
本文介绍了在 Scala 中提升函数值的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

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

例如,假设我想提升 String.length.我可以写

val f: String =>整数 = _.length

val f = { s: String =>s.length }

然而,这种语法并不总是理想的(尤其是在较大的表达式中).我想我正在寻找可以启用诸如

之类的表达式的东西

电梯[字符串](_.length)Lift[Option[Int]].lift(_.filter)

我想到了这样的事情:

class Lift[T] {def apply[R](f: T => R): T =>R = fdef 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(_)(_,_)//... 等等. ...}物体提升{def apply[T] = new Lift[T]}

问题 1:标准库(或任何库)是否提供这样的功能?

问题 2:如果不是,是否可以将其编写成 Option.filter 可以像上面一样提升(而不是 Lift[Option[Int]].lift[Int => Boolean, Option[Int]](_.filter))?如果没有在 lift 方法上提供类型参数,我会收到以下错误:

错误:缺少扩展函数的参数类型 ((x$1) => x$1.filter)Lift[Option[Int]].lift(_.filter)^

更新:

显然,我遇到的问题与重载的 lift 方法有关.如果我重命名重载,我可以提升 Option.filter 而无需所有额外的类型参数.

解决方案

我终于想出了一个令我满意的解决方案.此版本支持简单的语法和 API 的单一入口点,同时还提供对提升函数形式的控制(即非柯里化、部分柯里化或完全柯里化).

示例:

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

class Foo {def m1:整数 = 1def m2(i: Int): Int = idef m3(i: Int, j: Int): Int = i + j}

最简单的提升形式是将方法作为部分应用函数返回,相当于调用((_: Foo).method _):

scala>Lift[Foo](_.m1)//注意:不需要尾随 _res0: (Foo) =>Int = <function1>标度>Lift[Foo](_.m2 _)//注意:需要尾随 _res1: (Foo) =>(Int) =>Int = <function1>标度>电梯[Foo](_.m3 _)res2: (Foo) =>(Int, Int) =>Int = <function1>//注意:结果是部分柯里化的

通过导入一些隐式,可以请求柯里化或非柯里化形式:

scala>{|导入 CurriedLiftables._|电梯[Foo](_.m3 _)|}res3: (Foo) =>(Int) =>(Int) =>Int = <function1>标度>{|导入 UncurredLiftables._|电梯[Foo](_.m3 _)|}res4: (Foo, Int, Int) =>Int = <function3>

实施:

class Lift[T] {def apply[R,F](f: T => R)(隐式e: (T => R) Liftable F): F = e.lift(f)}物体提升{def apply[T] = new Lift[T]}class Liftable[From, To](val lift: From => To)类 DefaultLiftables {隐式 deflift[F]: F Liftable F = new Liftable(identity)}对象 Liftable 扩展了 DefaultLiftables类 UncurriedLiftable1 扩展了 DefaultLiftables {隐式 deflift1[T, A, R]: (T => A => R) Liftable ((T, A) => R) =new Liftable( f => f(_)(_) )}类 UncurriedLiftable2 扩展 UncurriedLiftable1 {隐式 deflift2[T, A1, A2, R]: (T => (A1, A2) => R) Liftable ((T, A1, A2) => R) =新的 Liftable ( f => f(_)(_,_) )}//UncurriedLiftable3, UncurriedLiftable4, ...对象 UncurriedLiftables 扩展了 UncurriedLiftable2类 CurriedLiftable2 扩展 DefaultLiftables {隐式 deflift2[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, ...对象 CurriedLiftables 扩展 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}类 Lift1[T] {def apply[A, R](f: (T) => (A) => R): (T, A) =>R =F(_)(_)}类 Lift2[T] {def apply[A1, A2, R](f: (T) => (A1, A2) => R): (T, A1, A2) =>R =F(_)(_,_)}//... 等等. ...物体提升{deflift0[T] = 新 Lift0[T]deflift1[T] = 新 Lift1[T]deflift2[T] = 新 Lift2[T]//... 等等. ...}

Does the Scala library provide any support for lifting a method of a given type to a function value?

For example, suppose I want to lift String.length. I can write

val f: String => Int = _.length

or

val f = { s: String => s.length }

However, this syntax is not always ideal (particularly in the midst of a larger expression). I think I'm looking for something that will enable expressions like

Lift[String](_.length) Lift[Option[Int]].lift(_.filter)

and I have in mind something like this:

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] }

Question 1: Does the standard library (or any library) provide something like this?

Question 2: If not, is it possible to write it in such a way that Option.filter can be lifted as above (rather than as Lift[Option[Int]].lift[Int => Boolean, Option[Int]](_.filter))? Without supplying the type parameters on the lift method I get the following error:

error: missing parameter type for expanded function ((x$1) => x$1.filter) Lift[Option[Int]].lift(_.filter) ^

Update:

Apparently, the problem I'm running in to has something to do with the overloaded lift method. If I rename the overloads, I can lift Option.filter without all the extra type parameters.

解决方案

I finally came up with a solution that I'm happy with. This version supports simple syntax and a single entry point to the API, while also providing control over the form of the lifted function (i.e. uncurried, partly curried, or fully curried).

Examples:

I'll use the following class definition in the examples below:

class Foo { def m1: Int = 1 def m2(i: Int): Int = i def m3(i: Int, j: Int): Int = i + j }

The simplest form of lifting is to return the method as a partially applied function, equivalent to invoking ((_: Foo).method _):

scala> lift[Foo](_.m1) // NOTE: trailing _ not required res0: (Foo) => Int = <function1> scala> lift[Foo](_.m2 _) // NOTE: trailing _ required res1: (Foo) => (Int) => Int = <function1> scala> lift[Foo](_.m3 _) res2: (Foo) => (Int, Int) => Int = <function1> // NOTE: the result is partly curried

By importing some implicits, one can request curried or uncurried forms:

scala> { | import CurriedLiftables._ | lift[Foo](_.m3 _) | } res3: (Foo) => (Int) => (Int) => Int = <function1> scala> { | import UncurriedLiftables._ | lift[Foo](_.m3 _) | } res4: (Foo, Int, Int) => Int = <function3>

Implementation:

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

My previous solution required a separate lift method for each arity:

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

Implementation:

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. ... }

更多推荐

在 Scala 中提升函数值的方法

本文发布于:2023-11-25 23:24:42,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1631765.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:函数   方法   Scala

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!