请考虑以下代码:
fnListToStrs vs fs = (\x -> snd $ x vs) <$> fs
这三个函数的类型只是部分变化 - 它们完全可用,而不需要知道它们产生的元组的第一个组件的类型。这意味着我可以对它们进行操作而无需参考该类型:
fnListToStrs
将这些定义加载到GHCi中,所有这三个函数都作为*Imprec> fnListToStrs [1,2] [t1,t2]
["2","??"]
*Imprec> fnListToStrs [1,2] [t3]
["1+1"]
的参数独立工作,实际上我可以传入包含t1和t2的列表,因为它们具有相同的类型:
*Imprec> fnListToStrs [1,2] [t1,t2]
["2","??"]
*Imprec> fnListToStrs [1,2] [t3]
["1+1"]
但是我无法同时通过所有3个,即使类型的分歧实际上与执行的计算无关:
fnListToStrs :: [Int] -> [forall a.[Int]->(a,String)] -> [String]
我觉得让这项工作与存在性或不可预测的类型有关,但是当使用我希望fnListToStrs能够采用的类型声明时,这两种扩展都不适合我,即:
{{1}}
还有其他方法可以让这项工作吗?
答案 0 :(得分:3)
任何将这些功能放入列表的方法都需要&#34;包装&#34;他们每个人都以某种方式。最简单的包装只是
wrap :: (a -> (b, c)) -> a -> c
wrap f = snd . f
确实还有其他方法来包装这些(特别是存在类型),但是你没有给出任何信息来暗示这些信息在你的应用程序中比这个最简单的版本更好。< / p>
这是一个更复杂的东西可能有意义的例子。假设你有
data Blob a b = Blob [a -> b] [a]
现在假设您想要列出Blob a b
类型的值,这些值都具有相同的b
类型,但可能有不同的a
类型。实际上将每个函数应用于每个参数可能会导致一个非常大的潜在结果列表,因此编写
data WrapBlob b where
WrapBlob :: Blob a b -> WrapBlob b
现在你可以制作清单并推迟决定哪些功能适用于哪个参数而无需支付过高的代价。
答案 1 :(得分:3)
存在是正确的,而不是不可预测的。并且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"]