简体   繁体   English

haskell中的多态函数列表?

[英]List of polymorphic functions in haskell?

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

These three functions have a type that only varies partially -- they are entirely usable without needing to know the type of the first component of the tuple they produce. 这三个函数的类型只是部分变化 - 它们完全可用,而不需要知道它们产生的元组的第一个组件的类型。 This means that I can operate on them without needing to refer to that type: 这意味着我可以对它们进行操作而无需引用该类型:

fnListToStrs vs fs = (\x -> snd $ x vs) <$> fs

Loading these definitions into GHCi, all three of the functions work independently as an argument to fnListToStrs , and indeed I can pass in a list containing both t1 and t2 because they have the same type: 将这些定义加载到GHCi中,所有这三个函数都作为fnListToStrs的参数独立工作,实际上我可以传入包含t1和t2的列表,因为它们具有相同的类型:

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

But I can't pass all 3 at the same time, even though the divergence of types is actually irrelevant to the calculation performed: 但我无法同时传递所有3个,即使类型的分歧实际上与执行的计算无关:

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

I have the feeling that making this work has something to do with either existential or impredicative types, but neither extension has worked for me when using the type declaration I expect fnListToStrs to be able to take, namely: 我觉得使这项工作与存在性或不可预测的类型有关,但是当使用我期望fnListToStrs能够采用的类型声明时,这两种扩展都不适用于我,即:

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

Is there some other way to make this work? 有没有其他方法使这项工作?

Any way to put these functions into a list will require "wrapping" each of them in some fashion. 将这些函数放入列表的任何方法都需要以某种方式“包装”它们。 The simplest wrapping is just 最简单的包装就是

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

There are, indeed, other ways to wrap these (notably with existential types), but you've not given any information to suggest that any of those would be even slightly better in your application than this simplest version. 实际上还有其他方法来包装这些(特别是存在类型),但是你没有给出任何信息来暗示这些信息在你的应用程序中会比这个最简单的版本稍微好一些。

Here's an example where something more sophisticated might make sense. 这是一个更复杂的东西可能有意义的例子。 Suppose you have 假设你有

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

Now imagine you want to make a list of values of type Blob ab that all have the same b type, but may have different a types. 现在假设你想要列出一个类型为Blob ab的值列表,它们都具有相同的b类型,但可能有不同a类型。 Actually applying each function to each argument could lead to a prohibitively large list of potential results, so it would make sense to write 实际上将每个函数应用于每个参数可能会导致一个非常大的潜在结果列表,因此编写它是有意义的

data WrapBlob b where
  WrapBlob :: Blob a b -> WrapBlob b

Now you can make the list and postpone the decision of which function(s) to apply to which argument(s) without paying a prohibitive price. 现在,您可以制作列表并推迟决定哪些函数适用于哪个参数而无需支付高昂的价格。

Existential is correct, not impredicative. 存在是正确的,而不是不可预测的。 And Haskell doesn't have existentials, except through an explicit wrapper... 并且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"]

but, this really is a bit useless. 但是,这真的有点无用。 Since you can't possibly do anything with the first result anyway, it's more sensible to just throw it away immediately and put the remaining function in a simple monomorphic list: 既然你不可能对第一个结果做任何事情,那么立即将它扔掉并将剩下的函数放在一个简单的单态列表中更为明智:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM