haskell中的多态函数列表?

Posted

技术标签:

【中文标题】haskell中的多态函数列表?【英文标题】:List of polymorphic functions in haskell? 【发布时间】:2016-03-22 20:20:40 【问题描述】:

考虑下面的代码:

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]

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

【问题讨论】:

【参考方案1】:

存在是正确的,而不是暗示性的。并且 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"]

【讨论】:

我的问题可能有点过于简单化了,这让我不确定如何实际应用它。在我的实际场景中,函数已经包装在一个类型中,但是两种结果类型都作为参数公开给该类型。我实际上需要制作一个忽略其中一个参数的列表,并且当我试图生成一个简化的 API 时,我宁愿客户端不需要自己使用显式包装器。但看起来这可能是不可能的......【参考方案2】:

任何将这些函数放入列表的方法都需要以某种方式“包装”它们中的每一个。最简单的包装就是

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中的多态函数列表?的主要内容,如果未能解决你的问题,请参考以下文章

Haskell代码编程

在 Haskell 中存储多态回调

为啥使用 null 函数而不是 == [] 来检查 Haskell 中的空列表?

Haskell,树中的列表列表

Haskell如何知道`xs`是函数定义中的列表?

为啥haskell中的递归列表这么慢?