是的,虽然不在 Haskell 中。但是高阶多态 lambda 演算(又名 System F-omega)更通用:
bi : forall m n a b. (forall a. m a -> n a) -> m a -> m b -> (n a, n b)
bi {m} {n} {a} {b} f x y = (f {a} x, f {b} y)
x1 : (Integer, Char)
x1 = bi {\a. List a} {\a. a} {Integer} {Char} head [2,3] "45"
x2 : (Integer, Char)
x2 = bi {\a . exists b. (a, b)} {\a. a} {Integer} {Char} (\{a}. \p. unpack<b,x>=p in fst {a} {b} x) (pack<Char, (2,'3')>) (pack<Integer, ('4',5)>)
x3 : (Integer, Double)
x3 = bi {\a. a} {\a. a} {Integer} {Double} (1+) 2 3.45
在这里,我为显式类型应用程序编写f {T}
并假设一个库分别被键入。类似的东西\a. a
是类型级别的 lambda。这个x2
例子更复杂,因为它还需要存在类型来本地“忘记”参数中的另一位多态性。
实际上,您可以在 Haskell 中通过newtype
为每个不同m
或n
您实例化的定义一个或数据类型来模拟这一点,并传递相应地f
添加和删除构造函数的适当包装的函数。但显然,这根本不好玩。
编辑:我应该指出,这仍然不是一个完全通用的解决方案。例如,我看不到您如何输入
swap (x,y) = (y,x)
x4 = bi swap (3, "hi") (True, 3.1)
即使在 System F-omega 中。问题是该swap
函数比bi
允许的多态性更强,并且与 with 不同x2
,结果中没有忘记其他多态维度,因此存在技巧不起作用。似乎您需要一种多态性来允许该多态性(以便参数bi
可以在不同数量的类型上是多态的)。