当前位置: 首页 > 面试题库 >

Java泛型:如何用Java编码Functor接口?

欧阳向文
2023-03-14
问题内容

我想用Java定义Functor类。这有效:

//a Function
public interface F<A,R> {
   public R apply(A a);
}

public interface Functor<A> {
   public <B> Functor<B> fmap(F<A,B> f);
}

但是,fmap的返回值应该不是Functor,而是适当的子类。通常,可以使用CRTP对此进行编码,但是由于附加参数,在这里我似乎遇到了麻烦A。例如,以下和类似的编码不起作用(“类型参数FInst不在其范围内”):

public interface Functor<A, FInst extends Functor<A,FInst>> {
    public <B, I extends Functor<B,FInst>> I fmap(F<A,B> f);
}

[说明]

对于“适当的子类”,我指的是被称为自身的类的类型。例如,列表是函子,所以我想写一些类似的东西

public class ListFunctor<A> implements ??? {
  final private List<A> list;
  public ListFunctor(List<A> list) {
     this.list = list;
  }

  @Override
  <B> ListFunctor<B> fmap(F<A,B> f) {
     List<B> result = new ArrayList<B>();
     for(A a: list) result.add(f.apply(a));
     return new ListFunctor<B>(result); 
  }  
}

我知道即使使用给出的第一个定义,我也可以编写此代码(因为允许使用协变量返回类型),但是我希望返回类型“ ListFunctor” 由类型系统
强制执行 (因此,我无法返回FooFunctor),这意味着Functor接口需要返回“自我类型”(至少在其他语言中如此)。

[结果]

所以看来我想要的是不可能的。这是一个相关的博客文章:http : //blog.tmorris.net/higher-order-
polymorphism-for-pseudo-java/

[后果]

我偶然发现了我这个古老的问题,意识到这是我的图书馆highJ令人惊叹的旅程的起点,该图书馆包含的内容远不止一个简单的Functor。我永远也不会想象人们会用这种疯狂的东西来处理任何严重的事情,但是事情发生了,这让我感到非常高兴。


问题答案:
public interface Functor<A, FInst extends Functor<A,FInst>> {
    public <B, I extends Functor<B,FInst>> I fmap(F<A,B> f);
}

这段代码会产生错误,因为您在定义时I将其定义为的子类Functor<B,FInst>,但Functor<B,FInst>在这种情况下FInst参数必须是的子类,而在上面将其定义为的子类Functor<A,FInst>。由于Functor<A,FInst>Functor<B,FInst>不兼容,因此会出现此错误。

我无法完全解决此问题,但我至少可以完成一半的工作:

import java.util.ArrayList;
import java.util.List;

interface F<A,R> {
   public R apply(A a);
}

interface Functor<A, FClass extends Functor<?, FClass>> {
   public <B> FClass fmap(F<A,B> f);
}

public class ListFunctor<A> implements Functor<A, ListFunctor<?>> {
  final private List<A> list;
  public ListFunctor(List<A> list) {
     this.list = list;
  }

  @Override
  public <B> ListFunctor<B> fmap(F<A,B> f) {
     List<B> result = new ArrayList<B>();
     for(A a: list) result.add(f.apply(a));
     return new ListFunctor<B>(result);
  }
}

这行得通,并且将允许的返回类型的集合适当地限制为ListFunctor,但并不将其限制为ListFunctor<B>仅子类。您可以将其声明为returning
ListFunctor<A>或任何其他ListFunctor,并且仍然可以编译。但是您不能将其声明为返回FooFunctor或任何其他Functor。

解决其余问题的主要问题是,您不能将FClass限制为的子类ListFunctor<B>,因为B参数是在方法级别而不是在类级别声明的,因此您不能编写

public class ListFunctor<A> implements Functor<A, ListFunctor<B>> {

因为那时B并不意味着任何东西。我也无法使它与fmap()的第二个参数一起使用,但是即使可以,它也会强制您两次指定返回类型-
在type参数中指定一次,在返回类型本身中再指定一次。



 类似资料:
  • 问题内容: 您如何进行这项工作: 不做 编辑 为什么这不起作用? 我正在将编译器消息标记为错误。 问题答案: Reimeus已经指出,您在编辑中要求的内容是不可能的。我只想扩展一下原因。 人们会认为您可以使用以下内容: 实际上,这就是我第一次看到这篇文章时想到的。但这实际上会导致编译器错误: 类型变量不能跟其他界限 为了帮助我解释原因,我想引用Victor Rudometov在OracleBlog

  • 编译时,此代码将产生以下+错误: 问题是访问中的类型T与列表中的T不相同。如何修复此编译问题?

  • 问题内容: 我有一个代表文本片段的泛型类。该文本片段可能具有多种不同模式(突出显示的不同类型)中的任何一种。这些模式用枚举表示。每个项目的Enum可能不同,但是它必须实现一个接口,该接口提供了一种将其中两个结合的方法(可以突出显示并加粗显示)。所以我有一个界面: 然后我的TextFragment是文本字符串和模式的容器。但是当我尝试声明该类时: 我收到以下错误: 令牌“扩展”的语法错误,预期 根据

  • 主要内容:泛型集合,泛型类,泛型方法,泛型的高级用法前面我们提到 Java 集合有个缺点,就是把一个对象“丢进”集合里之后,集合就会“忘记”这个对象的数据类型,当再次取出该对象时,该对象的编译类型就变成了 Object 类型(其运行时类型没变)。 Java 集合之所以被设计成这样,是因为集合的设计者不知道我们会用集合来保存什么类型的对象,所以他们把集合设计成能保存任何类型的对象,只要求具有很好的通用性,但这样做带来如下两个问题: 集合对元素类型没有

  • 本小节我们将学习 Java5 以后出现的一个特性:泛型(Generics)。通过本小节的学习,你将了解到什么是泛型,为什么需要泛型,如何使用泛型,如何自定义泛型,类型通配符等知识。 1. 什么是泛型 泛型不只是 Java 语言所特有的特性,泛型是程序设计语言的一种特性。允许程序员在强类型的程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须做出声明。 我们在上一小节已经了解到,Java

  • Pair泛型的实际参数类型是 Interger , 为什么不能赋值给 Number