不幸的是,目前没有通用的方法来做到这一点。你可以试试这样previous answer建议如下:
sum' :: Num b => (forall a. [a] -> b) -> [c] -> [d] -> b
sum' f l1 l2 = f l1 + f l2
虽然这适用于 length,但它并不能真正适用于其他很多东西。
问题在于此答案中的类型签名Num b => forall a. [a] -> b。这意味着您的函数必须适用于所有类型的列表,而 Num b => forall a. [a] -> b 中唯一合理的函数是 length。如果您认为还有其他示例,请随意给我一个示例,但我怀疑所有其他示例要么是长度的变化,要么是返回常量的愚蠢示例。
如果length 是sum' 的唯一合理参数,那么定义sum' 是愚蠢的,你不妨像下面这样定义sumLength
sumLength :: Num b => [c] -> [d] -> b
sumLength l1 l2 = genericLength l1 + genericLength l2
确实,让我们定义以下内容:
g :: Enum a => [a] -> Int
g = (foldl' 0 (+)) . (map fromEnum)
这是一个奇怪的可能没用的函数,但它做了一些不平凡的事情。它将所有值转换为它们的 Enum int 表示形式并将它们相加并输出一个整数。
所以sum' g l1 l2 应该可以工作,但不能。要让它工作,你必须定义一个新函数:
sum'' :: Enum c, Enum d => (Enum a => forall a. [a]) -> [c] -> [d] -> Int
sum'' f l1 l2 = f l1 + f l2
事实上,使用任何具有不同约束的函数,您都必须定义一个新版本的sum。
所以说真的,不,没有办法类似地回答你的问题。
我发现了这个问题并创建了包polydata,您可以在 hackage 上查看它(我承认需要一些更清晰的文档)。
它确实允许您制作接受多态函数的函数,您可以将这些函数应用于不同的类型,如下所示:
g :: (c (a -> a'), c (b -> b')) => Poly c -> (a, b) -> (a' -> b')
g f (x,y) = (getPoly f x, getPoly f y)
这与您的示例非常相似。
上面的c 是一个约束,查看g 的类型应该可以帮助您了解正在发生的事情。
不幸的是,您不能只将普通函数传递给g,您必须传递一个包裹在Poly 中的函数,这很重要,因为您无法获得Poly 约束的类型推断(任何关于如何使它变得更好的想法都值得赞赏)。
但是,如果您只有一个或几个需要这种多态行为的函数,我不会打扰Poly。但是例如,您发现这个问题出现了很多(我发现它在单元测试中出现了很多,这激发了我创建包的灵感),那么您可能会发现 polydata 很有用。
还有heterolist,我作为polydata 的扩展创建了它,它允许您创建混合类型的列表,并以类型安全的方式映射它们。您可能会发现这很有用。