问题标签 [higher-order-types]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
1 回答
120 浏览

java - “泛型”和“高阶类型”之间有什么关系?

来自这个问题:Scala 中的高级类型是什么?,我明白什么是higher-order types(也first-order typeproper type)。

但是还有一个问题:generics和“高阶类型”有什么关系?

我知道 Java 支持generics,这就像first-orderScala 中的类型。

以下哪项是正确的?

  1. 在 Scala 中,只有first-order typeisgenerics
  2. 在 Scala 中,first-order类型higher-order都属于generics
  3. 在Java中,generics只是平均first-order类型,它不完整
  4. genericsfirst-order是一个通用术语,意味着我们可以对类型进行“抽象” ,无论是higher-order
0 投票
1 回答
380 浏览

f# - 在 F# 中使用对象代数模拟更高种类的多态性

在论文Streams à la carte: Extensible Pipelines with Object AlgebrasBiboudis 等人。概述使用对象代数“模拟类型构造器多态性”的方法。

我正在尝试使用此方法在 F# 中实现一个高阶示例,类似于 中描述的示例,Typed Tagless Final Interpreters并具有以下内容:

相关部分Brand Freshness描述了在类型构造函数中嵌套类。我对 F# 的翻译如下:

但是,我得到了错误The type 't' is not defined

在 F# 中写这个的正确方法是什么?

0 投票
2 回答
825 浏览

haskell - 可以在类型级别上对函数进行模式匹配,但在值级别上却不行,为什么会有这种差异?

在SPJ 的这篇论文的第 3 页和第 4 页中,写道:

和:

类声明现在引入了类型函数 Ref(具有指定的种类)以及通常的值函数,例如 newRef(每个都具有指定的类型)。类似地,每个实例声明都提供了一个子句,该子句定义实例类型的类型函数以及每个值函数的见证。

我们说 Ref 是一个类型族,或类 Mutation 的关联类型。它的行为类似于 类型级别的函数,因此我们也将 Ref 称为类型函数。应用类型函数使用与应用类型构造函数相同的语法:上面的 Ref ma 表示将类型函数 Ref 应用于 m,然后将生成的类型构造函数应用于 a。

所以,换句话说,

Ref :: (*->*)->*->*

也就是说,Ref将类型级别函数作为参数,如Maybeor IOor[]并生成另一个类型级别函数,例如IORef使用模式匹配,即Ref模式匹配定义。

那么,怎么可能在类型级别而不是值级别上对函数进行模式匹配呢?

例如,

不可能写,因为函数的相等性是不可判定的。

1)那么在类型级别上这怎么可能没有问题呢?

2)是因为类型级别的功能非常有限吗?因此,类型级别上的任何类型的函数都不能作为参数Ref,只有少数选择,即程序员声明的函数,而不是像 (+) 这样的函数,它们比程序员声明的函数更通用?这就是类型级别函数模式匹配没有问题的原因吗?

3) 这个问题的答案是否与GHC 规范的这一部分有关?

0 投票
3 回答
3154 浏览

java - 为什么 Java 中不能声明 Monad 接口?

在你开始阅读之前:这个问题不是关于理解 monad,而是关于识别 Java 类型系统的限制,它阻止了Monad接口的声明。


在我努力理解 monad 的过程中,我阅读了 Eric Lippert 的这个SO-answer 关于一个关于 monad 的简单解释的问题。在那里,他还列出了可以在 monad 上执行的操作:

  1. 有一种方法可以获取未放大类型的值并将其转换为放大类型的值。
  2. 有一种方法可以将未放大类型的操作转换为放大类型的操作,该操作遵循前面提到的函数组合规则
  3. 通常有一种方法可以将未放大的类型从放大的类型中恢复出来。(最后一点对于 monad 不是绝对必要的,但经常存在这样的操作。)

在阅读了有关 monad 的更多信息后,我将第一个操作确定为return函数,将第二个操作确定为bind函数。我找不到第三个操作的常用名称,所以我将它称为unbox函数。

为了更好地理解 monad,我继续尝试Monad在 Java 中声明一个泛型接口。为此,我首先查看了上面三个函数的签名。对于 Monad M,它看起来像这样:

return函数不在 的实例上执行M,因此它不属于Monad接口。相反,它将被实现为构造函数或工厂方法。

同样,现在,我从接口声明中省略了该unbox函数,因为它不是必需的。对于接口的不同实现,这个函数会有不同的实现。

因此,Monad接口只包含bind功能。

让我们尝试声明接口:

有两个缺陷:

  • bind函数应该返回具体的实现,但是它只返回接口类型。这是一个问题,因为我们在具体子类型上声明了拆箱操作。我将此称为问题 1
  • bind函数应该检索一个函数作为参数。我们稍后会解决这个问题。

在接口声明中使用具体类型

这解决了问题 1:如果我对 monad 的理解是正确的,那么该bind函数总是返回一个与调用它的 monad 具有相同具体类型的新 monad。因此,如果我有一个Monad名为 的接口的实现M,那么M.bind将返回另一个M但不返回Monad. 我可以使用泛型来实现它:

起初,这似乎可行,但至少有两个缺陷:

  • 一旦实现类不提供自己而是提供Monad接口的另一个实现作为类型参数,这就会崩溃M,因为这样该bind方法将返回错误的类型。例如

    将返回一个实例MonadImpl,它应该返回一个FaultyMonad. 但是,我们可以在文档中指定此限制,并将此类实现视为程序员错误。

  • 第二个缺陷更难解决。我将其称为问题 2:当我尝试实例化类时,MonadImpl我需要提供M. 让我们试试这个:

    要获得有效的类型声明,这必须无限进行。这是另一个尝试:

    虽然这似乎可行,但我们只是将问题推迟到被调用方。这是该功能对我有用的唯一用法:

    这基本上归结为

    但这显然不是我们想要的。

在自己的声明中使用带有移位类型参数的类型

现在,让我们将函数参数添加到bind函数中: 如上所述,bind函数的签名如下所示:T1 -> M<T2>. 在 Java 中,这是类型Function<T1, M<T2>>。这是第一次尝试用参数声明接口:

我们必须将类型T1作为泛型类型参数添加到接口声明中,以便我们可以在函数签名中使用它。第一个?T1返回的 monad 类型M。要将其替换为T2,我们必须将T2其自身添加为泛型类型参数:

现在,我们遇到了另一个问题。我们在接口中添加了第三个类型参数Monad,所以我们必须添加一个新?的来使用它。我们将暂时忽略新?的,而首先研究现在?。它是M返回的 monad 类型M。让我们尝试?通过重命名并引入另一个M来删除它:M1M2

引入另一个T3结果:

并引入另一个M3结果:

我们看到,如果我们尝试解决所有问题,这将永远持续下去?。这是问题 3

总结一下

我们发现了三个问题:

  1. 在抽象类型的声明中使用具体类型。
  2. 实例化一个接收自身作为泛型类型参数的类型。
  3. 声明一个在其声明中使用自身的类型,并带有移位的类型参数。

问题是:Java 类型系统中缺少什么特性?由于有些语言可以使用 monad,因此这些语言必须以某种方式声明Monad类型。这些其他语言如何声明Monad类型?我无法找到有关此的信息。我只找到有关具体单子声明的信息,例如Maybe单子。

我错过了什么吗?我可以用 Java 类型系统正确解决这些问题之一吗?如果我不能用 Java 类型系统解决问题 2,那么 Java 没有警告我关于不可实例化类型声明的原因是什么?


如前所述,这个问题与理解单子无关。如果我对 monads 的理解是错误的,你可能会给出提示,但不要试图给出解释。如果我对单子的理解是错误的,那么所描述的问题仍然存在。

这个问题也不是关于是否可以Monad在 Java 中声明接口。这个问题已经得到了 Eric Lippert 在上面链接的 SO-answer 中的回答:不是。这个问题是关于阻止我这样做的究竟是什么限制。Eric Lippert 将此称为高级类型,但我无法理解它们。

大多数 OOP 语言没有足够丰富的类型系统来直接表示 monad 模式本身;您需要一个支持比泛型类型更高的类型的类型系统。所以我不会尝试那样做。相反,我将实现表示每个 monad 的泛型类型,并实现表示您需要的三个操作的方法:将值转换为放大值,将放大值转换为值,以及将未放大值上的函数转换为放大的值。

0 投票
1 回答
504 浏览

type-systems - 高阶类型与高阶类型的消歧

在上一个问题中,我问为什么不能在 Java 中声明 Monad 接口?. 在那里,我收到了 Brian Goetz 的评论,说我应该将“高阶类型”称为“高阶类型”。

现在,我阅读了更多关于类型系统的内容,并且理解了更高种类的类型的概念。但是,我仍然对这些条款感到困惑。我试图自己使用谷歌来消除它们的歧义,但似乎没有一个明确的答案。因此,我的问题是以下术语的确切含义是什么:

  • 高阶类型
  • 高级类型
  • 高阶种类

这三个术语都存在吗?它们之间有区别吗?有什么区别?编程语言之间的含义是否有所不同?

我还注意到 StackOverflow 有多个标签:

但是,它们都没有标签 wiki。

0 投票
1 回答
53 浏览

haskell - 映射受约束的存在限定的高阶类型

我希望我的术语是正确的。

我想做以下事情:

不幸的是,GHC 似乎无法正确推断约束并抱怨:

这有可能吗?

0 投票
1 回答
142 浏览

haskell - 我可以为 a -> b -> * 写一个更高阶的类型吗?

我知道这(->) a是一种高阶类型* -> *,当应用于类型参数时b会给出类型a -> b

我可以写一种类型* -> *,当应用于时c会给出a -> b -> c

如果不是,为什么不呢?也许使用一些语言扩展和forall

这将让我编写函数结构为“”的 Functor 和 Applicative(以及其他类)的实例,a -> b ->如下所示:

这将作为二进制(咖喱)函数的组合器很有用。

注意。也许这是与类型 (* -> *) -> * 相关的 Functors 和 Applicatives但我不确定,因为它超出了我的想象 :-)

0 投票
2 回答
300 浏览

haskell - 有没有办法在 Haskell 中捕获一组高阶函数?

我知道在 Haskell中不可能对函数进行模式匹配,我完全理解为什么。但是,我有两个密切相关的问题。首先,如果您想部分应用函数以供以后使用,如果它是一个元组,是否有定义和捕获返回的方法?还是我错了,这仍在尝试在我的眼皮底下匹配功能?

例如,假设我试图获得一个十的多个倍数的商和余数。那么,我该如何写这样的东西呢?

我在这里意识到,存在单独的功能,所以我可以这样做:

但是,这是一个非常特殊的情况,并且有无数其他返回元组的函数示例可以很好地概括。例如,返回列表中偶数和奇数的函数。

这引出了我的第二个问题。以上在 GHCi 中工作得很好。

更令人困惑的是,它甚至可以通过“模式匹配”来工作,就像我一开始玩的一样(q, r)

它在加载到 GHCi 的实际文件中也可以正常工作,即使(evens, odds)没有。为什么这两个不同,如果第二个不能正常工作,为什么在 GHCi 中工作?可以以某种方式利用这里的不同之处吗?

0 投票
2 回答
99 浏览

java - 在 Scala/Java 中允许参数化的类/类型

我想将域实体(如在域驱动设计中)中的属性定义为具有最大长度的字符串类型。不同的属性将有不同的最大长度(以便它可以匹配数据库列数据类型)。例如,描述将是 VARCHAR2(50),而长描述将是 VARCHAR2(200)。

是否可以定义一个像 VARCHAR2(50) 这样的参数采用整数的类型?所以我只需要为所有这些类型定义一个类并将其用于不同的属性?val 描述:TextValue(50) val longDescription:TextValue(200)

0 投票
1 回答
86 浏览

scala - 具有多个类型的类型的函子实现

假设我有:

我希望能够映射结果类型 B,即我希望能够做到:

我知道我应该实现一个Functor实例,Get但我很挣扎,因为我不知道要使用什么类型的签名。

我尝试了以下方法:

  • implicit val functor:Functor[Get] = ???

  • implicit val functor: Functor[Lambda[(F[_], K, A) => Get[F, K, A]]] = ???

但它们似乎不是正确的类型,因为我似乎无法使用顶部所示的仿函数语法扩展。在这里表达类型的正确方法是什么?如果我使用kind-projector插件,等效类型是什么?