我们知道Map接口对数学中的函数抽象进行建模。我应该如何对多变量函数建模?例如,对于模型f(x,y,z),我有两个选择:
Map<List<Integer>, Integer> f1;
或
Map<Integer, Map<Integer, Map<Integer, Integer>>> f2;
你认为哪一个更好?
谢谢,
发布于 2009-07-12 01:44:12
都不是。
你要找的技术叫做uncurrying。我们知道一个函数代表一种逻辑蕴含:
∀ a b. a -> b
我们还知道,如果A和B暗示C,那么A暗示B暗示C:
∀ a b c. ((a, b) => c) <=> (a => b => c)
Here's proof.查看真值表中的逻辑蕴含,你会发现它们是等价的。那么如何在类型级别表示A and B
呢?您可以使用产品类型。两种类型的乘积是一对,即值同时具有以下两种类型的类型:
interface P2<A, B> { public A _1(); public B _2(); }
您可以对三元组或任意大小的元组执行相同的操作。但是要注意,因为这样的推理会导致异类列表,这就是aren't pretty in Java。
此外,您的Map
表示只适用于部分函数。更重要的是,JDK的Map
接口被设计为可变的,谁听说过可变函数呢?下面是一个更好的表示:
interface F<A, B> { public B apply(A a); }
发布于 2009-07-12 01:02:53
第三个选项是定义一个简单的类,其中包含三个Integer
字段x
、y
和z
(例如,将其称为Triple
),并使用Map<Triple, Integer>
。
如果你经常需要这样的东西,你可以使Triple
本身泛型,并使用Map<Triple<Integer>, Integer>
(或者如果你的一些“函数”需要不同类型的参数,它甚至可以是一个Map<Triple<Integer, Integer, Integer>, Integer>
,但这开始失去可读性)。
发布于 2009-08-02 13:48:47
你的第一选择通常更好,因为它需要更少的内存和更少的代码来访问:
Map<List<Integer>, Integer> f1 = ...
f1.put(Arrays.asList(1, 2, 3), 7);
Integer v = f1.get(Arrays.asList(1, 2, 3));
仅当访问模式需要时才使用映射的映射,例如
Map<Integer, Map<Integer, Map<Integer, Integer>>> f2 = ...
Set<Integer> keys = f2.keySet();
https://stackoverflow.com/questions/1115052
复制相似问题