[英]Operations on n-th argument of curried functions in scala
我正在使用許多curried函數,采取類似的論點,但不完全。 出於這個原因,我發現有一種方法可以執行第n個參數的轉置,應用和組合,以及“最終”結果。 例:
val f :X=>Y=>W=>Z
def compose1[A](w :A=>Y) :X=>A=>W=>Z
def transpose1 :X=>W=>Y=>Z
def apply1(y :Y) :X=>W=>Z
對於n的固定值,可以很容易地完成它,如下所示:
implicit class Apply2[X, Y, Z](private val f :X=>Y=>Z) extends AnyVal {
def transpose :Y=>X=>Z = { y :Y => x :X => f(x)(y) }
def provide(y :Y) :X=>Z ={ x :X => f(x)(y) }
def compose[A](y :A=>Y) : X=>A=>Z = { x :X => a :A => f(x)(y(a)) }
def apply[A, B]()(implicit ev :Z <:< (A=>B)) :Apply3[X, Y, A, B] = new Apply3[X, Y, A, B]((x :X) => (y :Y) => ev(f(x)(y)))
}
但是我當然不歡迎復制 - 粘貼這個類的22個版本的想法。 對於帶有類型類的最后一個參數,我也可以很容易地做到這一點,但是類似於scala的下划線表示法部分應用非curry函數的解決方案可以解雇我。 我覺得應該有可能實現以下目標:
val f :A=>B=>C=>D=>E=>F
val c = f()().compose( (x :X) => new C(x)) :A=>B=>X=>D=>E=>F
val t = f()().transpose :A=>B=>D=>C=>E=>F
val s = f()().set(new C()) :A=>B=>D=>E=>F
通過隱式轉換為一些Apply
,它提供了一個遞歸的apply()
方法,返回一個嵌套的Apply
實例。
當所有類型都是已知的時,轉換為HList並返回的粗暴解決方案起作用,但是不確定的'依賴性是一把雙刃劍。
好吧,我的思緒仍然癢但我終於明白了! 但是,我在一段時間內做了最困難的編程任務。 如果有人有改進的建議(包括命名,符號和一般語法),我會全神貫注。
/** Represents a partially applied, curried function `F` which is of the form `... X => A`,
* where X is the type of the first argument after (partial) application.
* Provides methods for manipulating functions `F` around this argument.
* @tparam F type of the manipulated function in a curried form (non-empty sequence of single argument lists)
* @tparam C[G] result of mapping partial result `(X=>A)` of function `F` to `G`.
* @tparam X type of the argument represented by this instance
* @tparam A result type of function F partially applied up to and including argument X
*/
abstract class Curry[F, C[G], X, A](private[funny] val f :F) { prev =>
/** Result of partial application of this function F up to and including parameter `X`. */
type Applied = A
/** Replace X=>A with G as the result type of F. */
type Composed[G] = C[G]
/** A function which takes argument `W` instead of `X` at this position. */
type Mapped[W] = Composed[W=>A]
/** Provide a fixed value for this argument, removing it from the argument list.
* For example, the result of `Curry{a :Any => b :Byte => c :Char => s"$a$b$c" }().set(1.toByte)`
* (after inlining) would be a function `{a :Any => c :Char => s"$a${1.toByte}$c" }`.
*/
def set(x :X) :Composed[A] = applied[A](_(x))
/** Change the type of this argument by mapping intended argument type `W` to `X` before applying `f`.
* For example, given a function `f :F <:< D=>O=>X=>A` and `x :W=>X`, the result is `{d :D => o :O => w :W => f(d)(o)(x(w)) }`.
*/
def map[W](x :W=>X) :Composed[W=>A] = applied[W=>A]{ r :(X=>A) => (w :W) => r(x(w)) }
/** Map the result of partial application of this function up to argument `X` (not including).
* For example, if `F =:= K=>L=>X=>A`, the result is a function `{k :K => l :L => map(f(k)(l)) }`.
* @param map function taking the result of applying F up until argument `X`.
* @return resul
*/
def applied[G](map :((X => A) => G)) :Composed[G]
/** If the result of this partial application is a function `A <:< Y=>Z`, swap the order of arguments
* in function `F` from `=>X=>Y=>` to `=>Y=>X=>`.
*/
def transpose[Y, Z](implicit ev :A<:<(Y=>Z)) :Composed[Y=>X=>Z] = applied[Y=>X=>Z] {
r :(X=>A) => y :Y => x :X => ev(r(x))(y)
}
/** Skip to the next argument, i.e return an instance operating on the result of applying this function to argument `X`. */
def apply[Y, Z]()(implicit ev :this.type<:<Curry[F, C, X, Y=>Z]) = new NextArg[F, C, X, Y, Z](ev(this))
/** Skip to the next argument, i.e return an instance operating on the result of applying this function to argument `X`.
* Same as `apply()`, but forces an implicit conversion from function types which `apply` wouldn't.
*/
def __[Y, Z](implicit ev :this.type<:<Curry[F, C, X, Y=>Z]) = new NextArg[F, C, X, Y, Z](ev(this))
}
/** Operations on curried functions. */
object Curry {
type Self[G] = G
type Compose[C[G], X] = { type L[G] = C[X=>G] }
/** Extension methods for modifying curried functions at their first argument (and a source for advancing to subsequent arguments. */
@inline def apply[A, B](f :A=>B) :Arg0[A, B] = new Arg0(f)
/** Implicit conversion providing extension methods on curried function types. Same as `apply`, but doesn't pollute namespace as much. */
@inline implicit def ImplicitCurry[A, B](f :A=>B) :Arg0[A, B] = new Arg0(f)
/** Operations on the first argument of this function. */
class Arg0[X, Y](x :X=>Y) extends Curry[X=>Y, Self, X, Y](x) {
def applied[G](map: (X=>Y) => G) :G = map(f)
}
class NextArg[F, C[G], X, Y, A](val prev :Curry[F, C, X, Y=>A]) extends Curry[F, (C Compose X)#L, Y, A](prev.f) {
override def applied[G](map: (Y => A) => G): prev.Composed[X => G] =
prev.applied[X=>G] { g :(X=>Y=>A) => x :X => map(g(x)) }
}
}
def f :Byte=>Short=>Int=>Long=>String = ???
import Curry.ImplicitCurry
f.set(1.toByte) :(Short=>Int=>Long=>String)
f.map((_:String).toByte) :(String=>Short=>Int=>Long=>String)
f.__.set(1.toShort) :(Byte=>Int=>Long=>String)
Curry(f)().map((_:String).toShort) : (Byte=>String=>Int=>Long=>String)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.