[英]haskell: calling a function with different types of lists
我有一个功能:
sum f l1 l2 = (f l1) + (f l2)
当用不同类型的列表调用时,如何使此函数正常工作? 例如:
sum length [1,2] ['a','b']
也可以在回答中充实我的评论。 可能会尝试给出的通常的签名是
sum :: Num b => ([a] -> b) -> [a] -> [a] -> b
sum f l1 l2 = f l1 + f l2
这里的问题是两个列表必须具有相同的类型,该类型必须是函数的输入类型。 解决方案是告诉GHC,该函数实际上对于所有forall a. [a] -> b
具有更通用的类型forall a. [a] -> b
forall a. [a] -> b
,这意味着我们可以选择多个可能不同 a
实例,并且它们都产生相同的b
。
{-# LANGUAGE RankNTypes #-}
sum' :: Num b => (forall a. [a] -> b) -> [c] -> [d] -> b
sum' f l1 l2 = f l1 + f l2
main = print $ sum' length [1,2] ['a','b']
不幸的是,目前没有通用的方法可以做到这一点。 您可以尝试像下面这样的先前答案 :
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
。 这意味着您的函数必须适用于所有类型的列表,并且Num b => forall a. [a] -> b
唯一有意义的函数Num b => forall a. [a] -> b
Num b => forall a. [a] -> b
是length
。 如果您认为还有一个例子可以给我,但是我怀疑所有其他例子都是长度的变化或愚蠢的返回常数。
如果length
是sum'
的唯一明智的论点,那么定义sum'
是很愚蠢sum'
,您sumLength
好像下面这样定义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
表示形式,并对它们求和并吐出一个Integer。
因此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软件包,您可以检查黑客事件(我承认需要一些更清晰的文档)。
它确实允许您制作接受多态函数的函数,这些函数可以应用于不同的类型,如下所示:
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
不会让我感到困扰。 但是例如,您发现这个问题很多(我发现在单元测试中这个问题很多,这就是创建软件包的灵感),然后您可能会发现多数据很有用。
还有一个异类列表 ,我将其创建为多数据的扩展,它使您可以创建混合类型的列表,并以一种类型安全的方式映射它们。 您可能会发现有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.