Scala 中的类型级编程

2024-01-06

我想更深入地了解 Scala 中的类型级编程,因此我开始做一些小练习。我从类型级别的皮亚诺数的实现开始。这是下面的代码!

sealed trait PeanoNumType { // Type at the end indicates to the reader that we are dealing with types
  type plus[That <: PeanoNumType] <: PeanoNumType
}

sealed trait ZeroType extends PeanoNumType {
  type plus[That <: PeanoNumType] = That
}

sealed trait NextType[This <: PeanoNumType] extends PeanoNumType {
   type plus[That <: PeanoNumType] = NextType[This#plus[That]]
}

现在的问题是,上述实施会给我带来什么?我该如何利用它?


只要您需要自己创建这些类型,它就不会为您提供太多帮助。但是,一旦你让编译器为你做这些事情,它就会变得更有用。

在展示这一点之前,让我们将皮亚诺算术的表示方式改为更短的方式:

sealed trait Num
case object Zero extends Num
case class Succ[N <: Num](num: N) extends Num

然后,您可以创建具有编译时已知大小的列表:

sealed abstract class List[+H, N <: Num](val size: N) {
  def ::[T >: H](value: T): List[T, Succ[N]] = Cons(value, this)
}
case object Nil extends List[Nothing, Zero.type](Zero)
case class Cons[+H, N <: Num](head: H, tail: List[H, N]) extends List[H, Succ[N]](Succ(tail.size))
type ::[+H, N <: Num] = Cons[H, N]

如果您检查使用 sych 列表创建的某物的类型,它将在其类型中编码大小:

val list = 1 :: 2 :: 3 :: 4 :: Nil // List[Int, Succ[Succ[Succ[Succ[Zero.type]]]]] = Cons(1,Cons(2,Cons(3,Cons(4,Nil))))

接下来您可以尝试做的事情是使用隐式来检查某些内容,例如

trait EvenNum[N <: Num]
implicit val zeroIsEven = new EvenNum[Zero.type] {}
implicit def evenNPlusTwo[N <: Num](implicit evenN: EvenNum[N]) = new EvenNum[Succ[Succ[N]]] {}

这样,您就可以强制执行某些操作,只有在可以提供隐式证据时才能完成:

def operationForEvenSizeList[T, N <: Num](list: List[T, N])(implicit ev: EvenNum[N]) = {
  // do something with list of even length
}

operationForEvenSizeList(1 :: 2 :: Nil) // ok
operationForEvenSizeList(1 :: 2 :: 3 :: Nil) // compiler error

据我所知,当您开始使用隐式创建新类型时,Scala 中类型级编程的真正威力就会显现出来:可用于隐式证据、类型类派生和删除某些结构样板的类型。

Shapeless 是一个对泛型编程有很大帮​​助的库。我相信,一旦您用隐含的类型类派生进行一两个练习,这对您来说将是一件有趣的事情。

回到您的代码:您可以提供一些隐式变量,这些隐式变量将为您生成并提供类的实例。另外,除了创建新类之外,这段代码还会做其他事情,例如组合您要添加到这些类中的元素列表,或者提供从 PeanoNumType 到 Int 的转换,或者添加一些在编译时工作的谓词,等等。天空是极限。

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

Scala 中的类型级编程 的相关文章

随机推荐

  • 将驱动程序对象的单个实例传递给所有其他类(Testng 框架)

    我有一个在类示例中初始化的驱动程序对象 我也想将驱动程序对象传递给其他类 但我得到一个空指针异常 我的代码是 样本类 public class sample WebDriver driver Test priority 1 public v
  • 用于 POST 请求的 Django Rest 框架自定义过滤器

    在filters py中 我有一个CustomFilter定义了具有类型值的ComboSortFilter and IntegerListFilter 在views py中 我定义了一个ViewSet 它具有filter class Cus
  • 我可以使用在启动期间配置的 MvcJsonOptions 在自定义中间件中进行序列化吗?

    我正在构建一个带有用于全局异常处理的中间件的 ASP NET Core Api 在Startup类中 我配置了一些用于所有控制器的 JSON 选项 public void ConfigureServices IServiceCollecti
  • TensorFlow 的内存泄漏

    我的 TensorFlow 出现内存泄漏 我提到了Tensorflow 即使关闭会话也会发生内存泄漏 https stackoverflow com questions 35695183 tensorflow memory leak eve
  • Vue.js filterBy 在多个字段中搜索

    如何通过在多个搜索键中搜索来进行过滤 我正在尝试这样的事情 但是 当然 它不会起作用 tr AFAIK 没有记录 filterBy 自定义过滤器 但您可以使用method制作你自己的过滤器 var demo new Vue el demo
  • 只能使用绝对 URI 作为基地址

    请帮助获得例外using ServiceHost host new ServiceHost typeof HelloService HelloService 在下面的代码中 例外 只有绝对 URI 可以用作基地址 WCF 主机应用程序 cl
  • Redis 尝试连接到 Heroku 上的本地主机而不是 REDIS_URL

    我有一个 Rails 应用程序 它使用 Redis 进行后台作业 在 Heroku 上 我使用 Heroku Redis 插件 当我部署到 Heroku 时 出现以下错误 Redis CannotConnectError Error con
  • 为什么Android开发中一定要把这个Context作为参数传递呢?

    这是来自developer android com 上的课程 public void sendMessage View view Intent intent new Intent this DisplayMessageActivity cl
  • 打印对象如何会导致与 str() 和 repr() 不同的输出?

    我正在解释器上测试一些代码 我注意到一些意外的行为sqlite3 Row http docs python org library sqlite3 html sqlite3 Row class 我的理解是print obj总是会得到相同的结
  • django-compressor 离线生成错误

    我正在尝试使用 django compressor 压缩我的 CSS 文件 但我不断收到此错误 compressor exceptions OfflineGenerationError You have offline compressio
  • 如何在 React Navigation 中刷新

    一旦我删除用户令牌 用户就会重定向到登录页面 但是如果我用其他用户登录 主页仍然显示以前的用户信息 这是因为我没有刷新主页 如何在反应导航中手动重新初始化 主页 MainPage Logged in as matt gt Logout gt
  • 从后台工作人员更新 GUI

    问题的名称是 从后台工作人员更新 GUI 但正确的名字是 world 从后台工作人员更新 GUI 或从后台工作人员报告多个变量 整数除外 请让我解释一下我的情况 在一个程序中 我有一个后台工作人员来分析信息 分析的结果是 表单 GUI 元素
  • 像 root 用户一样运行 PHP shell_exec()

    我构建了一个 PHP 应用程序 在其中为 Linux debian Jessie 创建命令行功能 一切正常 但我需要能够使用一些命令 例如 root 用户 有没有办法使用 shell exec 或类似的命令通过 PHP 像 root 用户一
  • postgres 中的顺序扫描和位图堆扫描有什么区别?

    在解释命令的输出中 我发现了两个术语 顺序扫描 和 位图堆扫描 有人可以告诉我这两种扫描有什么区别吗 我使用的是PostgreSql http www postgresql org docs 8 2 static using explain
  • Node.js 和express.js 中基于组/规则的授权方法

    Express js 中基于角色的授权有哪些好的策略 特别是对于快递资源 With 快递资源 https github com visionmedia express resource没有处理程序 所以我认为有三种选择 使用中间件 将授权函
  • 服务器管理 - 需要脚本来监控服务器上的可用空间

    需要脚本来监控服务器上的可用空间如果可用内存空间达到某个阈值发送警报邮件 PS 我认为解决方案是 Power Shell Windows Timer Job 不过我对 Power Shell 还很陌生 您可以使用如下命令获取可用磁盘空间 w
  • PHP 中的日历日视图

    我正在努力向现有日历解决方案添加日视图选项 像许多实现自己的日历的人一样 我正在尝试对 Google 日历进行建模 他们有一个出色的日历解决方案 并且他们的日视图提供了很大的灵活性 大多数情况下 实施进展顺利 然而 当涉及到冲突事件时 我遇
  • 如何更改DataGridView中某些单元格的边框颜色?

    我需要编程更改 CellFormatting 事件中某些单元格的边框颜色 单个单元的板颜色可以更改吗 你可以画一个矩形 在此示例中 我在选定的单元格上放置了红色边框 private void dataGridView CellPaintin
  • 客户端服务器udp套接字

    您好 我有一个 udp 客户端服务器代码无法正常工作 我问一个一般性问题 Shane 是个好孩子吗 这两个代码都没有出现错误 但是当我运行它输出的代码时 数据报发送数据包 新的 DatagramPacket sendData sendDat
  • Scala 中的类型级编程

    我想更深入地了解 Scala 中的类型级编程 因此我开始做一些小练习 我从类型级别的皮亚诺数的实现开始 这是下面的代码 sealed trait PeanoNumType Type at the end indicates to the r