Scala 中的高级类型 [重复]

2024-06-01

我正在阅读 Scala 中的函数式编程一书,在 Monoids 章节中,他们讨论了 Monoid 接口,如下所示:

trait Monoid[A] {
 def op(a1: A, a2: A): A
 def zero: A
}

后来,他们通过扩展这个接口来定义特定的 Monoid 实例。例如。,

val intMonoid = new Monoid[Int] {
  ...
}

val listMonoid = new Monoid[List[Int]] {
  ...
}

我在第 10 章中读了几页,我遇到了“更高级的类型”,根据这本书,它是任何类型,它本身就是可以接受其他类型的类型。

trait Foldable[F[_]] {
 ...
 ...
}

因此,根据本书,可折叠特征是一种更高级的类型。我的问题是,Monoid[A] 对我来说也符合“更高种类类型”的定义,因为它可以采用 List[A]。我的理解正确吗?如果不是,是什么让更高种类的类型成为 Scala 中更高种类的类型?

编辑:所以一元类型构造函数接受一个参数并生成一个类型。那么这里的这个案例呢?

def listMonoid[A] = new Monoid[List[A]] {
  ...
  ...
}

那么我的 listMonoid 函数是 HKT 吗?


一些术语:

  • 正确的类型(例如 Int)
  • 一阶类型(例如 List[_]);我们也可以说一阶类型
  • 更高种类的类型(例如 Monad[M[_])

当你说

trait Monoid[A] {
  def op(a1: A, a2: A): A
  def zero: A
}

val listMonoid = new Monoid[List[Int]] {
  def op(l: List[Int], l2: List[Int]) =  List(1,2)
  def zero = List(1,2)
}

你正在参数化Monoid具有某种类型 A 的特征,它可以(如您所注意到的)是一个简单类型,也称为正确类型(例如Int)或参数化类型(例如List[Int], 甚至List[Set[Map[Int, Int]])。这使得Monoid一阶类型。我们也可以说它是一个一元类型构造函数 - 它需要一种类型来生成最终类型。

与 Monoid 不同,一些抽象(例如 Monad)需要由类型构造函数参数化。 Int 不再起作用了。它需要是“某种可以产生另一种类型的类型”。由类型构造函数参数化的抽象(即由“一阶类型”参数化)是高等类型。这是一个例子:

trait Monad[M[_]] {
  def op[A, B](m: M[A], f: A => M[B]): M[B]
  def zero[A](a: A): M[A]
}

object ListMonad extends Monad[List] {
  def op[A, B](m: List[A], f: A => List[B]) = m.flatMap(f)
  def zero[A](a: A) = List[A](a)
}

val listMonad = ListMonad.zero(42)
val result = ListMonad.op(listMonad, (i: Int) => List(i - 1, i, i + 1))

// result = List(41, 42, 43)

So Monad参数化为一阶类型(一元类型构造函数),这使得Monad本身就是一个高等类型.

注意如何Monad并不真正关心类级别上的“内部类型”本身,因为它将由方法定义op and zero。你也可以说trait Monad[M[A]]并在类的定义点“修复”类型 AListMonad(例如将其修复为 Int),但随后你就会失去灵活性(你的ListMonad然后将只能构造和 flatMapList[Int]你需要一个不同的课程,比如说,List[String]).

这与 Monoid 不同,Monoid 不是更高级的类型;它不需要类型构造函数来生成类型。如果它需要它,那么你永远不会拥有,比如说,Monoid[Int],因为 Int 不是类型构造函数。

另请注意我是如何说 Monad 需要一个unary类型构造函数,这意味着它只需要一种类型(不像 Map 需要两种类型)。类型构造函数通常用星号和箭头表示:

  • 一元一阶类型构造函数是* -> *(它采用单一类型并生成最终类型,例如 Set)
  • 二进制一阶类型构造函数是* -> * -> *(二进制类型构造函数,采用两种类型来生成最终类型,例如 Map)
  • 一元高级类型是(* -> *) -> *(采用单个一元类型构造函数来生成最终类型,例如 Monad)

etc.

因此,一阶类型采用简单/具体/适当的类型并生成最终类型,而高级类型则高一级;它需要一阶类型来生成最终类型。

EDIT:

在“编辑”部分回答您的问题:好的,我想我知道什么让您感到困惑。listMonoid不是一种类型,因此它不可能是更高级的类型。这是一种方法。Monad[List[Int]]是完全解析的类型。Monad[F[A]]也得到彻底解决。然而,Monad本身是一个高阶类型。

让我将其与函数进行类比。如果你有一个函数foo(x: Int),然后函数调用如foo(42) or foo(someIntegerValue)产生具体的价值。这些类似于Monad[List[Int]] and Monad[F[A]]。然而,foo本身就是一个函数,就像Monad本身是一个类型构造函数。

If foo采用一个简单值(不是函数),它是一阶函数;如果它接受或返回一个函数,那么它是一个高阶函数。与类型构造函数相同。如果它采用简单类型,则它是一阶类型构造函数。例子:List。如果它采用另一个类型构造函数,则它是高阶类型构造函数(也称为高种类类型)。例子:Monad.

不要将解析类型与类型构造函数混合。思考功能是否有意义foo是否是高阶的;这取决于它的参数和返回类型。但思考是否foo(42)是否是高阶的;这不是一个函数,而是一个函数应用,从而产生值。Monad[List[Int]]不是类型构造函数,而是类型构造函数的应用List到类型构造函数Monad(这是高阶的)。相似地,Monoid[List[Int]]不是类型构造函数,而是类型的应用List[Int]到类型构造函数Monoid(这是一阶)。类型构造函数更高阶的称为 HKT。谈论 HKT 并指向具体的解析类型(由于应用某种类型构造函数而创建)是没有意义的。

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

Scala 中的高级类型 [重复] 的相关文章

随机推荐

  • 逻辑应用的 IP 白名单

    如何将逻辑应用的 IP 地址列入白名单 由逻辑应用程序调用的服务 使用 HTTP 操作 但该服务需要白名单才能调用 那么 如何将逻辑APP列入白名单呢 我们可以使用Azure API管理进行白名单 它发布逻辑App 因为api管理提供静态I
  • Unix shell脚本找出脚本文件所在的目录?

    基本上我需要使用与 shell 脚本文件位置相关的路径运行脚本 如何将当前目录更改为与脚本文件所在的目录相同 在 Bash 中 你应该得到你需要的东西 如下所示 usr bin env bash BASEDIR dirname 0 echo
  • Rails - 可以在 javascript 函数中设置 Rails 变量吗?

    在 javascript 函数中设置 Rails 变量有什么问题吗 我无法在谷歌上搜索到明确的答案 只是想确保没有我不知道的陷阱或缺陷 我实际上对它是如何工作的感到困惑 如果 javascript 在客户端执行 我不会假设 Rails 会在
  • 如何将元素的每个单词包装在span标签中?

    div date contents filter function return this nodeType 1 wrap span span 我是新手 认为代码可以解决问题 但它将所有内容都包含在 span 像这样 div class d
  • 加速 Chromium 构建

    我正在使用 Visual Studio 2010 在 Windows 上构建 Chromium 我遵循了在尽可能 短 的时间内构建 Chromium 的所有建议 http www chromium org developers how to
  • 更改工具栏中汉堡图标的大小?

    我有两个问题 可能很奇怪 但无论如何 我有带有应用程序标题的工具栏 如何将其更改为非徽标的图片 下一个问题 是否可以设置 更改工具栏中汉堡图标的大小 我在下面的下一个代码的帮助下制作了经典的导航抽屉 我也使用了 ActionBarDrawe
  • 这个结果背后的逻辑是什么?

    def foo override end p foo bye bye p foo hello world Output override hello 我可以理解如果结果是 override world or even bye bye hel
  • Tomcat:源服务器没有找到目标资源的当前表示,或者不愿意透露该表示的存在[重复]

    这个问题在这里已经有答案了 我知道以前有类似的问题 但我仍然找不到正确的解决方案 我得到 源服务器没有找到目标资源的当前表示 或者不愿意透露该表示的存在 我正在使用 Tomcat 服务器 有人可以帮助我吗 以下是我的项目结构 我被这个问题困
  • Google API Oauth2:所有用户只有一个刷新令牌?

    我正在使用 OAuth2 身份验证 并且我有一个包含多个用户的 CMS 每个用户都有自己的配置文件 碰巧我们公司有一个 Google 帐户 可以访问多个 Analytics 帐户 对于使用 CMS 的每个用户 我使用不同的用户名连接到 Go
  • 未初始化变量的值是如何确定的?

    给定一个程序 int main short myVariableName1 stores from 32768 to 32767 short int myVariableName2 stores from 32768 to 32767 si
  • 开始使用 Chef,并在部署时运行 Composer 安装

    我们希望部署一些Laravel4 http laravel com使用 OpsWorks 在亚马逊上基于 PHP 应用程序 这需要满足以下条件 从 git 抓取代码 从 getcomposer com 下载composer phar Run
  • 在asp.net core mvc中,小数的模型绑定不接受千位分隔符

    对于具有decimal属性 如果来自客户端的值包含逗号作为千位分隔符 则模型绑定将失败 我们该如何解决这个问题呢 任何解决方案 全局 控制器 操作本地或模型 属性本地 都是好的 我有一个解决方法 那就是有一个string读取和写入的属性de
  • ExitFullScreen 不起作用 + 无论如何要按键盘单击按钮?

    我的浏览器 Google Chrome 版本 33 0 1750 154 m Script function exitFullscreen var element document documentElement if element mo
  • Flutter:在 Android 上获取本地 IP 地址

    如何在 Flutter 中获取我的 Android 设备的本地 IP 地址 这应该是 当连接到 WIFI 时 我的路由器通过 DHCP 分配的本地 IP 地址 如果连接到 VPN 则由我的 VPN 服务器分配的 VPN 网络中的本地 IP
  • 基本 dyplr 函数给出错误:“check_dots_used”

    试图找出为什么我会收到此错误 以前从未见过 谷歌没有帮助 check dots used action warn 中的错误 未使用参数 action warn 我在下面的非常基本的试验中收到错误 而且在 group by count 中也收
  • 类验证器 (Node.js) 在自定义验证中获取另一个属性值

    目前 我有一个非常简单的类验证器文件 其中包含 Nest js 中的 ValidationPipe 如下所示 import IsDateString IsEmail IsOptional IsString Length Max from c
  • Silverlight 4 中使用显式样式进行运行时主题切换

    有人要求我们向我们的应用程序添加动态主题切换 但我在弄清楚如何执行此操作时遇到了问题 目前的情况是这样的 我们的应用程序有一个具有显式 非隐式 样式的合并资源字典 我们应用程序中的视图通过以下方式引用这些样式StaticResource标记
  • 启动 Twitter 应用程序 [重复]

    这个问题在这里已经有答案了 可能的重复 Twitter 应用程序的 Android Intent https stackoverflow com questions 2077008 android intent for twitter ap
  • 使用“严格引用”时不能使用字符串作为 ARRAY 引用

    我正在尝试执行下面提到的代码并观察到错误 在使用 严格引用 时 无法使用字符串 RCSoWLAN ePDG 2 Qguest ASUS ATT 作为 ARRAY 引用 Perl代码 perl64 bin perl use strict us
  • Scala 中的高级类型 [重复]

    这个问题在这里已经有答案了 我正在阅读 Scala 中的函数式编程一书 在 Monoids 章节中 他们讨论了 Monoid 接口 如下所示 trait Monoid A def op a1 A a2 A A def zero A 后来 他