Consider the code below:
t1 :: [Int] -> (Int,String)
t1 xs = (sum xs,show $ length xs)
t2 :: [Int] -> (Int,String)
t2 xs = (length xs, (\x -> '?') <$> xs)
t3 :: [Int] -> (Char,String)
t3 (x:xs) = ('Y',"1+" ++ (show $ length xs))
t3 [] = ('N',"empty")
这三个函数的类型只有部分变化——它们完全可以在不知道它们产生的元组的第一个组件类型的情况下使用。这意味着我可以在不需要引用该类型的情况下对它们进行操作:
fnListToStrs vs fs = (\x -> snd $ x vs) <$> fs
将这些定义加载到 GHCi 中后,这三个函数都可以独立地作为 fnListToStrs
的参数工作。实际上,我可以传入一个包含 t1 和 t2 的列表,因为它们具有相同的类型:
*Imprec> fnListToStrs [1,2] [t1,t2]
["2","??"]
*Imprec> fnListToStrs [1,2] [t3]
["1+1"]
但是我不能同时通过所有三个测试,尽管类型的分歧实际上与所执行的计算无关:
*Imprec> fnListToStrs [1,2] [t1,t2]
["2","??"]
*Imprec> fnListToStrs [1,2] [t3]
["1+1"]
我有一种感觉,让这个工作起来与存在类型或难以预测的类型有关,但是当使用我期望fnListToStrs能够接受的类型声明时,这两个扩展都没有起作用:
fnListToStrs :: [Int] -> [forall a.[Int]->(a,String)] -> [String]
有没有其他方法使这个工作?