加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

在Scala中使用foldLeft应用参数列表到curried函数

发布时间:2020-12-16 09:41:07 所属栏目:安全 来源:网络整理
导读:可以在参数列表上执行foldLeft,其中提供给fold的初始值是完全curried函数,运算符应用,列表是要传递给函数f的参数列表? 例如,假设f定义为: scala val f = (i: Int,j: Int,k: Int,l: Int) = i+j+k+lf: (Int,Int,Int) = Int = function4 我们当然可以直接
可以在参数列表上执行foldLeft,其中提供给fold的初始值是完全curried函数,运算符应用,列表是要传递给函数f的参数列表?

例如,假设f定义为:

scala> val f = (i: Int,j: Int,k: Int,l: Int) => i+j+k+l
f: (Int,Int,Int) => Int = <function4>

我们当然可以直接使用:

scala> f(1,2,3,4)
res1: Int = 10

或者一次咖喱和应用一个参数:

scala> f.curried
res2: Int => Int => Int => Int => Int = <function1>

scala> f.curried.apply(1).apply(2).apply(3).apply(4)
res3: Int = 10

乍看起来,这看起来像foldLeft的工作。

我第一次尝试使用foldLeft描述这个应用序列,如下所示:

scala> List(1,4).foldLeft(f.curried)({ (g,x) => g.apply(x) })

但是,会产生以下错误:

<console>:9: error: type mismatch;
 found   : Int => Int => Int => Int
 required: Int => Int => Int => Int => Int
              List(1,x) => g.apply(x) })

我读错误消息是类型推断需要g的一些提示。

我正在寻找的解决方案是在原来的表达式中保留所有内容,除了g的类型:

List(1,4).foldLeft(f.curried)({ (g: ANSWER,x) => g.apply(x) })

我的第一个想法是,联盟类型在这里是有用的。我看过迈尔斯·萨宾是使用库里 – 霍华德派生的联盟类型,所以如果第一个预感是真的,那么我似乎有解决问题所需的基本机器。

但是:即使是联合类型的答案,如果我可以参考“所有类型的完全curried类型的函数到所有函数的类型,除了最后一个参数之外的所有类型”,这将是有用的。换句话说,一种打开类型的方式:

T1 => ... => Tn

进入联盟类型:

(T1 => ... => Tn) |∨| ... |∨| (Tn-1 => Tn)

将作为上述g的类型是有用的。

在列表上执行foldLeft将讨论限制在T1到Tn-1都相同的情况。一个符号

(T1 =>)+ Tn

将描述我想为g提供的类型。

我提出的具体案例不需要任意长链,所以我们可以在迭代器使用上提供界限

(T1 =>){1,4} Tn

展望未来,要为不相同类型的链条做这个,虽然也许有些类型的神奇功能将链条整合成所有后缀的集合更有用:

Suffixes(T1 => ... => Tn)

目前这样做远远超出了我的Scala能力。任何提示如何去做这样做将不胜感激。无论这可以通过高级使用Scala的现有类型系统还是通过编译器插件或两者都不能完成,我不知道。

如下面的注释所述,调用结果为“联合类型”不是完美适用于此用例。我不知道还有什么可以说的,但这是我目前最接近的想法。其他语言对这个想法有特别的支持吗?这在Coq和Agda将如何工作?

命名这个问题,并且了解它在更大的图像(类型理论,可判定性等)上的位置对于我来说比使用ANSWER的工作实现更重要,尽管两者都是不错的。奖金指向任何可以绘制与Scalaz,Monoids或类别理论联系的人。

解决方法

事实证明比我初步预期的要简单得多。

首先我们需要定义一个简单的HList,

sealed trait HList

final case class HCons[H,T <: HList](head : H,tail : T) extends HList {
  def ::[H1](h : H1) = HCons(h,this)
  override def toString = head+" :: "+tail.toString
}

trait HNil extends HList {
  def ::[H1](h : H1) = HCons(h,this)
  override def toString = "HNil"
}

case object HNil extends HNil
type ::[H,T <: HList] = HCons[H,T]

然后我们可以借助类型类来感应地定义我们的折叠函数,

trait FoldCurry[L <: HList,F,Out] {
  def apply(l : L,f : F) : Out
}

// Base case for HLists of length one
implicit def foldCurry1[H,Out] = new FoldCurry[H :: HNil,H => Out,Out] {
  def apply(l : H :: HNil,f : H => Out) = f(l.head)
}

// Case for HLists of length n+1
implicit def foldCurry2[H,T <: HList,FT,Out]
  (implicit fct : FoldCurry[T,Out]) = new FoldCurry[H :: T,H => FT,Out] {
    def apply(l : H :: T,f : H => FT) = fct(l.tail,f(l.head))
}

// Public interface ... implemented in terms of type class and instances above
def foldCurry[L <: HList,Out](l : L,f : F)
  (implicit fc : FoldCurry[L,Out]) : Out = fc(l,f)

我们可以这样使用,首先是你的原始例子,

val f1 = (i : Int,j : Int,k : Int,l : Int) => i+j+k+l
val f1c = f1.curried

val l1 = 1 :: 2 :: 3 :: 4 :: HNil

// In the REPL ... note the inferred result type
scala> foldCurry(l1,f1c)
res0: Int = 10

并且我们也可以使用相同的未修改的foldCurry来实现具有不同理论和非均匀参数类型的函数,

val f2 = (i : Int,s : String,d : Double) => (i+1,s.length,d*2)
val f2c = f2.curried

val l2 = 23 :: "foo" :: 2.0 :: HNil

// In the REPL ... again,note the inferred result type
scala> foldCurry(l2,f2c)
res1: (Int,Double) = (24,4.0)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读