HList 只不过是一种复杂的元组编写方式吗?

2024-03-17

我真的很想找出差异所在,更一般地说,是为了识别不能使用 HList 的规范用例(或者更确切地说,与常规列表相比不会产生任何好处)。

(我知道有 22 个(我相信)TupleN在 Scala 中,而只需要一个 HList,但这不是我感兴趣的概念差异。)

我在下面的文字中标记了几个问题。其实可能没有必要回答,更多的是指出我不清楚的地方,并引导讨论到一定的方向。

动机

我最近看到了一些关于 SO 的答案,人们建议使用 HLists (例如,由无形的 https://github.com/milessabin/shapeless),包括删除的答案这个问题 https://stackoverflow.com/questions/11815908/valid-type-casting-of-both-covariant-and-contravariant-class-at-runtime-in-scala。它引发了这次讨论 https://chat.stackoverflow.com/rooms/14938/discussion-between-mhs-and-edmondo1984,这又引发了这个问题。

Intro

在我看来,只有当您静态地知道元素的数量及其精确类型时,hlist 才有用。该数量实际上并不重要,但您似乎不太可能需要生成一个包含不同但静态精确已知类型的元素的列表,但您并不静态地知道它们的数量。问题一:你甚至可以写一个这样的例子,例如,在循环中吗?我的直觉是,拥有一个静态精确的 hlist 和静态未知数量的任意元素(相对于给定的类层次结构任意)是不兼容的。

HList 与元组

如果这是真的,即您静态地知道数字和类型 -问题2:为什么不直接使用 n 元组呢?当然,您可以安全地映射和折叠 HList(您也可以,但是not类型安全地,在以下命令的帮助下修改元组productIterator),但由于元素的数量和类型是静态已知的,您可能可以直接访问元组元素并执行操作。

另一方面,如果函数f您映射的 hlist 非常通用,它接受所有元素 -问题3:为什么不通过使用它productIterator.map?好吧,一个有趣的区别可能来自方法重载:如果我们有几个重载f的,拥有 hlist 提供的更强大的类型信息(与 ProductIterator 相比)可以允许编译器选择更具体的f。然而,我不确定这在 Scala 中是否真的有效,因为方法和函数不一样。

HList 和用户输入

基于相同的假设,即您需要静态地了解元素的数量和类型 -问题4:hlists 可以用在元素依赖于任何类型的用户交互的情况下吗?例如,想象一下用循环内的元素填充 hlist;从某个地方(UI、配置文件、参与者交互、网络)读取元素,直到满足某个条件。 hlist 的类型是什么?与接口规范 getElements: HList[...] 类似,它应该与静态未知长度的列表一起使用,并且允许系统中的组件 A 从组件 B 获取这样的任意元素列表。


解决问题一到三:主要应用之一HLists对数量进行抽象。数量通常在抽象的任何给定使用站点上都是静态已知的,但因站点而异。拿这个,来自无形的examples https://github.com/milessabin/shapeless/blob/master/examples/src/main/scala/shapeless/examples/flatten.scala#L70,

def flatten[T <: Product, L <: HList](t : T)
  (implicit hl : HListerAux[T, L], flatten : Flatten[L]) : flatten.Out =
    flatten(hl(t))

val t1 = (1, ((2, 3), 4))
val f1 = flatten(t1)     // Inferred type is Int :: Int :: Int :: Int :: HNil
val l1 = f1.toList       // Inferred type is List[Int]

val t2 = (23, ((true, 2.0, "foo"), "bar"), (13, false))
val f2 = flatten(t2)
val t2b = f2.tupled
// Inferred type of t2b is (Int, Boolean, Double, String, String, Int, Boolean)

不使用HLists(或等效的东西)对元组参数的数量进行抽象flatten不可能有一个单一的实现可以接受这两种截然不同的形状的参数并以类型安全的方式转换它们。

抽象元数的能力可能会在涉及固定元数的任何地方引起人们的兴趣:以及元组,如上所述,包括方法/函数参数列表和案例类。看here https://github.com/milessabin/shapeless/blob/master/examples/src/main/scala/shapeless/examples/monoids.scala例如,我们如何抽象任意案例类的数量以几乎自动获取类型类实例,

// A pair of arbitrary case classes
case class Foo(i : Int, s : String)
case class Bar(b : Boolean, s : String, d : Double)

// Publish their `HListIso`'s
implicit def fooIso = Iso.hlist(Foo.apply _, Foo.unapply _)
implicit def barIso = Iso.hlist(Bar.apply _, Bar.unapply _)

// And now they're monoids ...

implicitly[Monoid[Foo]]
val f = Foo(13, "foo") |+| Foo(23, "bar")
assert(f == Foo(36, "foobar"))

implicitly[Monoid[Bar]]
val b = Bar(true, "foo", 1.0) |+| Bar(false, "bar", 3.0)
assert(b == Bar(true, "foobar", 4.0))

没有运行时间迭代这里,但是有复制,其中使用HLists(或等效结构)可以消除。当然,如果您对重复样板的容忍度很高,则可以通过为您关心的每个形状编写多个实现来获得相同的结果。

在问题三中,您会问“...如果映射到 hlist 的函数 f 非常通用,它接受所有元素...为什么不通过 ProductIterator.map 使用它?”。如果您映射到 HList 的函数确实具有以下形式Any => T然后映射过来productIterator将为您提供完美的服务。但形式的功能Any => T通常不是那么有趣(至少,除非它们在内部进行强制类型转换)。 shapeless 提供了一种多态函数值的形式,它允许编译器以您怀疑的方式选择特定于类型的情况。例如,

// size is a function from values of arbitrary type to a 'size' which is
// defined via type specific cases
object size extends Poly1 {
  implicit def default[T] = at[T](t => 1)
  implicit def caseString = at[String](_.length)
  implicit def caseList[T] = at[List[T]](_.length)
}

scala> val l = 23 :: "foo" :: List('a', 'b') :: true :: HNil
l: Int :: String :: List[Char] :: Boolean :: HNil =
  23 :: foo :: List(a, b) :: true :: HNil

scala> (l map size).toList
res1: List[Int] = List(1, 3, 2, 1)

关于您的问题四,关于用户输入,有两种情况需要考虑。第一种情况是我们可以动态地建立一个上下文来保证获得已知的静态条件。在这些类型的场景中,完全有可能应用无形技术,但显然前提是如果静态条件doesn't在运行时获取然后我们必须遵循替代路径。毫不奇怪,这意味着对动态条件敏感的方法必须产生可选的结果。这是一个使用的示例HLists,

trait Fruit
case class Apple() extends Fruit
case class Pear() extends Fruit

type FFFF = Fruit :: Fruit :: Fruit :: Fruit :: HNil
type APAP = Apple :: Pear :: Apple :: Pear :: HNil

val a : Apple = Apple()
val p : Pear = Pear()

val l = List(a, p, a, p) // Inferred type is List[Fruit]

的类型l不捕获列表的长度或其元素的精确类型。但是,如果我们期望它具有特定的形式(即,如果它应该符合某些已知的固定模式),那么我们可以尝试建立该事实并采取相应的行动,

scala> import Traversables._
import Traversables._

scala> val apap = l.toHList[Apple :: Pear :: Apple :: Pear :: HNil]
res0: Option[Apple :: Pear :: Apple :: Pear :: HNil] =
  Some(Apple() :: Pear() :: Apple() :: Pear() :: HNil)

scala> apap.map(_.tail.head)
res1: Option[Pear] = Some(Pear())

在其他情况下,我们可能不关心给定列表的实际长度,除了它与其他列表的长度相同之外。同样,这是 Shapeless 支持的东西,既可以完全静态地支持,也可以在如上所述的混合静态/动态上下文中支持。看here https://github.com/milessabin/shapeless/blob/master/examples/src/main/scala/shapeless/examples/sized.scala一个扩展的例子。

正如您所观察到的,所有这些机制确实都需要静态类型信息可用,至少有条件地可用,并且这似乎排除了这些技术在完全动态环境中的使用,完全由外部提供的非类型化数据驱动。但随着 2.10 中支持运行时编译作为 Scala 反射的一个组件,即使这也不再是一个不可克服的障碍……我们可以使用运行时编译来提供一种形式轻量级舞台 https://github.com/milessabin/shapeless/blob/master/examples/src/main/scala/shapeless/examples/staging.scala并在运行时执行静态类型以响应动态数据:摘录自下面的内容...请点击链接查看完整示例,

val t1 : (Any, Any) = (23, "foo") // Specific element types erased
val t2 : (Any, Any) = (true, 2.0) // Specific element types erased

// Type class instances selected on static type at runtime!
val c1 = stagedConsumeTuple(t1) // Uses intString instance
assert(c1 == "23foo")

val c2 = stagedConsumeTuple(t2) // Uses booleanDouble instance
assert(c2 == "+2.0")

我敢肯定@PLT_波拉特 https://twitter.com/PLT_Borat鉴于他的关于依赖类型编程语言的圣人评论 https://twitter.com/PLT_Borat/status/163966991877685249 ;-)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

HList 只不过是一种复杂的元组编写方式吗? 的相关文章

  • 什么是 ZIO 错误通道以及如何了解要放入其中的内容?

    ZIO https zio dev https zio dev 是一个 scala 框架 其核心是ZIO R E A 数据结构及其站点给出了三个参数的以下信息 ZIO The ZIO R E A 数据类型具有三个类型参数 R 环境类型 该效
  • Spark JSON 文本字段到 RDD

    我有一个 cassandra 表 其中有一个名为 snapshot 的文本类型字段 其中包含 JSON 对象 identifier timestamp snapshot 我了解到 为了能够使用 Spark 对该字段进行转换 我需要将该 RD
  • Haskell - 交替两个列表中的元素

    我正在尝试编写一个 haskell 函数 它接受两个整数列表并生成一个列表 其中包含从两个列表中交替获取的元素 我有这个功能 blend xs ys 一个例子 blend 1 2 3 4 5 6 应该返回 1 4 2 5 3 6 我的逻辑是
  • Scala:不变性和路径依赖的类型兼容性

    我围绕这个主题提出了一些问题 但这次我想让它成为一个更一般性的讨论 因为在我看来 Scala 缺少一些非常重要的块 考虑以下代码 从我的真实项目中简化 trait World type State lt StateIntf def evol
  • SBT - 使用汇编时多项目合并策略和构建 sbt 结构

    我有一个由多个较小项目组成的项目 其中一些项目相互依赖 例如 有一个依赖于 commons 项目的实用程序项目 其他项目可能依赖于公用事业或公共设施 也可能不依赖于两者 在 build sbt 中 我在文件末尾有程序集合并策略 以及程序集中
  • Scala 函数作为对象与类

    trait MyFunctionTrait extends Int Int gt Double class MyFunction1 extends MyFunctionTrait override def apply a Int b Int
  • SQL Server 文本数据类型最大长度 = 65,535?

    我正在使用的软件使用文本字段来存储 XML 根据我的在线搜索 文本数据类型应该包含 2 31 1 个字符 目前 SQL Server 每次都会将 XML 截断为 65 535 个字符 我知道这是由 SQL Server 引起的 因为如果我直
  • 带有泛型参数的抽象类的 JsonFormat

    我正在尝试为具有通用参数的抽象类编写 JsonFormat 如下所示 abstract class Animal A def data A def otherStuff String stuff case class CatData cat
  • 条件运算符不能隐式转换?

    我对这个 C 的小怪癖有点困惑 给定变量 Boolean aBoolValue Byte aByteValue 编译如下 if aBoolValue aByteValue 1 else aByteValue 0 但这不会 aByteValu
  • 视图和流有什么区别?

    在Scala 2 8集合框架中 有什么区别view and toStream 在视图中 每次访问元素时都会重新计算它们 在流中 元素在求值时会被保留 例如 val doubled List 1 2 3 4 5 6 7 8 9 10 view
  • 在 scalaz 中免费实施

    Haskell 中的免费实现是 data Free f a Pure a Free f Free f a 而 Scalaz 中的实现是 sealed abstract class Free S A private case class Re
  • Python:检查对象是否是字符串列表

    如何检查一个对象是否是字符串列表 我只能检查对象是否是字符串 def checktype obj if isinstance obj str print It s a string obj1 foo bar bar black sheet
  • 将结构数组分解为 Spark 中的列

    我想将结构数组分解为列 由结构字段定义 例如 root arr array nullable true element struct containsNull true id long nullable false name string
  • Scala 中 Null/Nothing/Unit 的用法

    我刚刚读过 http oldfashionedsoftware com 2008 08 20 a post about nothing http oldfashionedsoftware com 2008 08 20 a post abou
  • 使用 Elastic4s 进行动态 ElasticSearch 映射

    我有一个文档要在elasticSearch上建立索引 该文档包含一些我事先无法知道的动态键 例如以下示例中的 西班牙语 或 法语 contents title spanish Hola amigos french Bonjour les a
  • Scala Continuations - 为什么我的转移调用不能位于 try-catch 块内?

    我对 Scala 延续很陌生 而且对一般的 scala 语言也比较陌生 我尝试使用 Scala 延续并编写了以下代码 case class MyException msg String extends Exception def go In
  • 使用 Either 处理 Scala 代码中的故障

    Optionmonad 是 Scala 中处理有或无事物的一种很好的表达方式 但是 如果在 什么也没发生 时需要记录一条消息怎么办 根据 Scala API 文档 Either 类型通常用作 scala Option where Left
  • e:B, f:(B,A)=>B) : B 是什么意思

    我对这意味着什么感到困惑 我理解柯里化 但我似乎无法完全阅读代码 def foldLeft A B xs List A e B f B A gt B B 只是几个建议 顺便说一句 里面没有柯里化 def foldLeft A B xs Li
  • Scala Monad - 完整的示例[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何在 AWS S3 中保存和使用 Spark History Server 日志

    我想在AWS S3中记录和查看Spark历史服务器的事件日志 以下是spark defaults conf中记录的属性 spark hadoop fs s3a impl org apache hadoop fs s3a S3AFileSys

随机推荐

  • PHP中的while循环问题

    我的标记结构如下 div div value1 div div value2 div div value3 div div value4 div div class clear div div div div value5 div div
  • ASP.NET 2.0 网站可以引用 WCF Web 服务吗?

    我们公司目前有一个网站部署在Windows 2000操作系统中 这意味着我们只能在该机器上安装 NET 2 0 升级网络服务器操作系统是不可能的 因为该网络服务器还托管我们国家的其他网络应用程序 作为我们 IT 政策的一部分 出于安全原因
  • 在内容级别与 google chrome 扩展一起使用时,未定义 DP_jQuery_*

    我正在开发一个谷歌浏览器扩展 我正在尝试在现有网页 内容级别 的 jquery ui 对话框中使用 jquery ui datepicker 就像这样 截屏 http sites google com site kamimark files
  • 如何获取最近经过身份验证的用户?

    我正在使用 MVC 3 并且刚刚实现了 FormsAuthenticationService 的包装器 类似于以下内容 public void SignIn string username bool createPersistantCook
  • 小程序中的 java.lang.reflect.invocacytargetexception 错误 [已关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我的应用程
  • 在 mongoose 中使用 mongodb 多键索引方法索引引用数组

    我的架构有一个 ObjectId 数组 它们是对另一个架构的引用 我想要的是使用 mongodb 的多键索引方法来索引这个数组条目 所以给定一个ObjectId中的某些文档的产品目录集合 我可以列出我当前集合中具有给定的所有文档Object
  • 如何防止 VS2010 在每次更新服务引用时创建新绑定?

    我正在使用 C 3 5 和 Visual Studio 2010 中的 WCF 服务开发 Winforms 客户端应用程序 每次我使用 更新服务参考 在 IDE 中 考虑到我已经有一个有效的绑定app config 会生成一个具有相同名称和
  • 通过公共API导出非公共类型

    如果我有几个返回非公共类型的工厂方法和提供此非公共类型变量的配对方法集怎么办 这会导致 NetBeans 中出现标题为警告消息的结果 结果公共 API 将只包含两个配对的方法集 原因是使我的类型层次结构密封 就像 Scala 中的密封类 并
  • 异步更新数据后重绘 UITableView

    我有一个 UITableview 我使用数据异步加载 因此 tableview 可能会显示没有数据 我已经厌倦了 ReloadData 方法 但表视图仍然为空 直到我滚动表视图 突然数据出现 当我将表视图加载为详细视图并在项目之间切换时 会
  • 如何在终端中查看 Heroku 应用程序的当前数据库架构?

    我试图在终端 Mac OS X Lion 中查看我的 Heroku 应用程序架构 并偶然发现了一个可以执行此操作的命令 在终端中 我运行heroku run more db schema rb但它似乎显示较旧的架构版本 我刚刚迁移了 Her
  • FileHelpers:不带引号的 CSV 中的可选字段

    我在用文件助手 http www filehelpers com从 CSV 文件导入数据 问题是 某些版本的 CSV 文件具有比其他版本更多的字段 因此 我已将有时丢失的字段标记为可选 但这似乎不起作用 因为它不仅仅是在字段丢失时忽略 这似
  • Powershell 截断 SQL 查询输出

    我正在从 powershell 命令运行以下查询 不幸的是 该查询在结果字符串的末尾截断或添加了点 我调整了 powershell 的屏幕缓冲区大小 即右键单击 powershell 属性 gt 布局 gt 屏幕缓冲区大小 gt 宽度和高度
  • 当应用程序强制关闭或设备重新启动时,共享首选项会重置数据

    我正在开发一个在其中存储的应用程序username and password in SharedPreferences 一切对我来说都工作正常 存储和检索值 但我发现 当我重新启动设备或应用程序被强制关闭时 存储在SharedPrefere
  • Node.js 如何删除文件中的第一行

    我正在制作简单的 Node js 应用程序 我需要删除文件中的第一行 请问有什么办法可以做到吗 我认为使用 fs write 是可能的 但是如何呢 这是从文件中删除第一行的流版本 由于它使用流 意味着您不需要将整个文件加载到内存中 因此它更
  • Java - 创建具有给定范围的 IntStream,然后使用映射函数随机化每个元素

    因此 我创建了一个 IntStream 为其指定了 1 9 的范围 我希望能够使用 map 函数获取给定范围 1 9 中的每个元素并随机化每个元素 本质上 我想在每次程序运行时以不同的顺序流式传输数字 1 9 我对其他想法持开放态度 但它必
  • Azure 表存储在插入时引发异常:(409) 冲突

    我正在使用 Azure 表存储从 MVC 应用程序记录访问者信息 但有时会引发以下异常 WebException The remote server returned an error 409 Conflict System Net Htt
  • 如何对公共接口背后高度复杂的代码进行单元测试

    我想知道应该如何通过 NUnit 测试此类功能 Public void HighlyComplexCalculationOnAListOfHairyObjects calls 19 private methods totalling 100
  • Laravel 5.2 身份验证不起作用

    正如你们所知 Laravel 5 2 几天前发布了 我正在尝试这个新版本 我在 CLI 上使用以下命令创建了一个新项目 laravel new testapp As per 身份验证快速入门文档 https laravel com docs
  • 如何使用 Javascript 打开新的隐身窗口? (谷歌浏览器)

    我想帮助我的朋友在执行一些鼠标手势 鼠标笔划 Chrome 扩展中的自定义笔划 时在新的隐身窗口中打开网站 Chrome 扩展程序tabs权限可以使用chrome windows create https developer chrome
  • HList 只不过是一种复杂的元组编写方式吗?

    我真的很想找出差异所在 更一般地说 是为了识别不能使用 HList 的规范用例 或者更确切地说 与常规列表相比不会产生任何好处 我知道有 22 个 我相信 TupleN在 Scala 中 而只需要一个 HList 但这不是我感兴趣的概念差异