在Scala中使用foldLeft应用参数列表到curried函数
可以在参数列表上执行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) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |