是否可以做一个foldLeft
在参数列表上,其中提供给折叠的初始值是完全柯里化函数,运算符是apply
,列表是要传递给函数的参数列表f
?
例如,假设 f 定义为:
scala> val f = (i: Int, j: Int, k: Int, l: Int) => i+j+k+l
f: (Int, 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
.
我第一次尝试描述这个序列apply
using foldLeft
好像:
scala> List(1, 2, 3, 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, 2, 3, 4).foldLeft(f.curried)({ (g, x) => g.apply(x) })
我对错误消息的阅读是类型推断需要一些提示g
.
我正在寻找的解决方案使原始表达式中的所有内容都保持不变,除了类型g
:
List(1, 2, 3, 4).foldLeft(f.curried)({ (g: ANSWER, x) => g.apply(x) })
我的第一个想法是联合类型在这里会很有用。我已经看到 Miles Sabin 使用 Curry-Howard 推导联合类型,所以如果第一个预感是真的,那么我似乎拥有解决问题所需的基本机制。
但是:即使联合类型是答案,如果我可以参考“从函数的完全柯里化类型到柯里化函数的类型(除了提供最后一个参数之外的所有参数)的所有类型的并集”,也会很有用。换句话说,一种转变类型的方法:
T1 => ... => Tn
进入联合类型:
(T1 => ... => Tn) |∨| ... |∨| (Tn-1 => Tn)
作为以下类型很有用g
above.
Doing a foldLeft
on a List
将讨论限制在以下情况T1
通过Tn-1
都是一样的。像这样的符号
(T1 =>)+ Tn
会描述我想要提供的类型g
.
我所询问的具体情况不需要任意长的链,因此我们可以使用以下方式提供迭代器的界限
(T1 =>){1,4} Tn
不过,展望未来,如果想要对不相等的类型链执行此操作,也许类型上的一些神奇函数将链分解为所有后缀的集合更有用:
Suffixes(T1 => ... => Tn)
目前实现这一点远远超出了我的 Scala 能力。任何有关如何进行此操作的提示将不胜感激。我不知道这是否可以通过 Scala 现有类型系统的高级使用或通过编译器插件来完成,或者两者都没有。
正如下面的评论中所指出的,将结果称为“联合类型”并不完美适合此用例。我不知道还能叫它什么,但这是我目前最接近的想法。其他语言对这个想法有特殊支持吗?这在 Coq 和 Agda 中如何工作?
对我来说,命名这个问题并理解它在更大的图景(类型理论、可判定性等)方面的位置比有效实现更重要ANSWER
,尽管两者都很好。任何能够与 Scalaz、幺半群或一般范畴论建立联系的人都会获得奖励积分。