在 Scala 中使用 FoldLeft 将参数列表应用于柯里化函数

2024-03-07

是否可以做一个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、幺半群或一般范畴论建立联系的人都会获得奖励积分。


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

首先我们需要定义一个简单的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, FT, 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, F, Out](l : L, f : F)
  (implicit fc : FoldCurry[L, F, 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, Int, Double) = (24,3,4.0)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Scala 中使用 FoldLeft 将参数列表应用于柯里化函数 的相关文章

随机推荐

  • 自定义 Django 字段来存储电子邮件地址列表

    我正在尝试向 Django 模型添加一个字段来表示电子邮件地址列表 我希望用户在管理中的表单中输入逗号分隔的地址列表 然后我的应用程序将解析该列表以发送一系列电子邮件 我当前的实现涵盖了基本思想 但有很大的局限性 在管理中 如果我输入类似的
  • 增加 JMeter 执行期间的线程数

    我有一个性能测试JMeter并想用它来测试最大系统性能 吞吐量 因此 当错误率低于 2 时 应增加活动线程数 我发现Constant Throughput Timer 把它放入Thread Group但它只会暂停或减慢线程 我尝试将其定义如
  • 从 Postman 向 Microsoft Bot 发送消息

    我正在尝试向我创建并发布到 azure 服务的机器人发送消息 以便该机器人可以开始向其某些用户发送消息 我尝试首先在 Postman 上发出请求 然后我可以为该交互构建一个控制器 我正在执行以下请求 POST https login mic
  • 单击手风琴中元素 id 的链接时打开 JQuery 手风琴

    这是我的问题http jsfiddle net uJ3W5 12 http jsfiddle net uJ3W5 12 正如您所看到的 顶部的 4 个按钮链接到手风琴第 1 部分中的元素 然而 当手风琴关闭时 这些链接不起作用 我需要它 这
  • 如何比较yaml文件中的键?

    有两个 Ruby on Rails 国际化 yaml 文件 一份文件完整 另一份文件缺少密钥 如何比较两个 yaml 文件并查看第二个文件中缺少的键 有没有工具可以做到这一点 假设file1是正确的版本并且file2是缺少密钥的版本 def
  • 将 VS2019 与 TFS2018 vnext 构建系统结合使用,无需服务器端解决方法

    我最近在尝试将 VS2019 与 TFS2018 vnext 构建系统一起使用时遇到了问题 在 Visual Studio Build 步骤中不能选择VS2019 选择 Latest 则不会使用Visual Studio 2019 在测试服
  • 是否可以对 feed 进行过滤

    是否可以对流中的提要实施过滤 我希望允许用户关注其他用户帖子 但将这些帖子标记为各种类别 我们的愿望是选择一个 足球 类别 并仅查看我关注的人发布的具有该标签的帖子 或者如果该类别是 所有体育 则可能是一个标签集合 查看 api 和文档 提
  • Spring集成:如何顺序处理文件

    我使用 int file inbound channel adapter 来加载目录中存在的文件 我喜欢按顺序处理文件 这意味着当第一个文件的处理完成时 我加载第二个文件 等等 I see a sample https github com
  • Firefox 中的无效日期 - Javascript

    我想将以下字符串 10 10 2013 03 04 放入 Date 对象中 它在 Chrome 中工作 但 Firefox 告诉我这是一个无效的日期 我猜他们的意思是格式 我尝试对其使用 Date parse 但这使其成为 NaN 该怎么办
  • 如何向表达式添加另一个条件?

    我有这样的表情 Expression
  • Mongoose - 如何分组和填充?

    我使用 MongoDB 和 Mongoose 作为我的 ODM 我尝试使用以下命令进行查询populate and group by在同一份声明中 这是我的简单文档模型 var userSchema new Schema username
  • 避免在 WooCommerce 购物车中组合虚拟和物理产品

    我已经寻找这个问题很长时间了 但似乎从未找到可能的解决方案 有谁看到任何解决方案如何在一个 Woocommerce 购物车中仅允许物理或虚拟产品 当客户尝试添加虚拟和物理的组合并禁止该组合时 或者确保该组合不能出现在一个购物车中时 可能会弹
  • 当网络连接关闭时,适用于 Android 的 Picasso 库是否可以处理图像加载?

    我正在开发一个我使用的应用程序毕加索图书馆 http square github io picasso 用于在我的中加载图像ViewPager和别的ImageViews 所以我想知道如果网络连接关闭会发生什么 库是否可以自行处理 或者我是否
  • 通过 C++ 互操作或其他方式实现 C# 第一类延续?

    我们有一个非常高性能的多任务 近乎实时的 C 应用程序 这一性能主要是通过使用自制的调度程序在内部实施协作多任务来实现的 这通常称为微线程 在这个系统中 所有任务都通过队列与其他任务通信 我们遇到的具体问题似乎只能通过 C 不支持的第一类延
  • 按部分函数与 lambda 映射列表

    我想知道对于大多数例子来说 它是否更 Pythonic 使用lambda http docs python org reference expressions html lambda or the partial http docs pyt
  • 如何仅从网站上刮掉 标记

    我正在研究网络爬虫 目前我抓取了整个内容 然后使用正则表达式删除
  • 读取数据文件时将任意列值传递到 D3 可视化

    我正在使用 D3 直方图可视化 并希望传递不一定名为 字母 或 频率 的标题 如果我尝试更改以下代码块中的列属性 则不会显示任何可视化效果 如何传入任意列名称 d3 tsv datapath type function error data
  • 如何从 Java 应用程序将 SQL 文件(存储在 Java 项目的源文件夹中)加载到 MySQL 中?

    我想在运行时将 SQL 文件 存储在 NetBeans Java 项目的源文件夹中 从我的 Java 应用程序加载到 MySQL 中 我怎样才能做到这一点 SQL 文件大小为 15 15 MB 我想知道是否可以复制到字符串中 或者 如果我无
  • 构建时 Swift 编译器分段错误

    添加 方便的 计算height财产给UIView in my UIViewExtension swift文件导致 Swift 编译器出现段错误 这里可能出了什么问题 0 swift 0x00000001061e5608 llvm sys P
  • 在 Scala 中使用 FoldLeft 将参数列表应用于柯里化函数

    是否可以做一个foldLeft在参数列表上 其中提供给折叠的初始值是完全柯里化函数 运算符是apply 列表是要传递给函数的参数列表f 例如 假设 f 定义为 scala gt val f i Int j Int k Int l Int g