haskell 中的多态函数列表?

List of polymorphic functions in haskell?

考虑以下代码:

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"]

但我不能同时通过所有 3 个,即使类型的差异实际上与执行的计算无关:

*Imprec> fnListToStrs [1,2] [t1,t2]
["2","??"]
*Imprec> fnListToStrs [1,2] [t3]
["1+1"]

我觉得使这项工作与存在类型或谓词类型有关,但是当使用我希望 fnListToStrs 能够采用的类型声明时,这两个扩展对我都不起作用,即:

fnListToStrs :: [Int] -> [forall a.[Int]->(a,String)] -> [String]

还有其他方法可以实现吗?

任何将这些函数放入列表的方法都需要 "wrapping" 每个函数以某种方式。最简单的包装就是

wrap :: (a -> (b, c)) -> a -> c
wrap f = snd . f

确实有其他方法来包装这些(特别是存在类型),但您没有提供任何信息表明这些方法在您的应用程序中甚至比这个最简单的版本稍微好一点。

这是一个示例,其中更复杂的内容可能有意义。假设你有

data Blob a b = Blob [a -> b] [a]

现在假设您想要创建一个类型为 Blob a b 的值列表,这些值都具有相同的 b 类型,但可能具有不同的 a 类型。实际上,将每个函数应用于每个参数可能会导致潜在结果的列表过大,因此编写

是有意义的
data WrapBlob b where
  WrapBlob :: Blob a b -> WrapBlob b

现在您可以制作列表并推迟决定将哪些函数应用于哪些参数,而无需付出过高的代价。

存在是正确的,不是强制性的。并且 Haskell 没有存在性,除非通过显式包装器...

{-# LANGUAGE GADTs #-}

data SomeFstRes x z where
  SFR :: (x -> (y,z)) -> SomeFstRes x z

> fmap (\(SFR f) -> snd $ f [1,2]) [SFR t1, SFR t2, SFR t3]
["2","??","1+1"]

但是,这个真的有点没用。由于无论如何您都无法对第一个结果做任何事情,因此更明智的做法是立即将其丢弃并将剩余的函数放入一个简单的单态列表中:

> fmap ($[1,2]) [snd . t1, snd . t2, snd . t3]
["2","??","1+1"]