如何写一个类型为`[(a,b)] - >的函数([a] - > [a]) - > [(A,B)]`

时间:2014-05-04 17:08:25

标签: haskell

我有一个关联列表

L :: [(a,b)]

每个a都与b相关联。

b只是额外信息,有趣的部分是a

我想使用a,因此我有f类型的函数[a] -> [a]。 (在我的问题中,我实际上有[a] -> [[a]],所以如果你的答案会推广到我可以遍历的任何容器,那将会很好。

我想我需要像

这样的东西
[(a,b)] -> ([a] -> T a) -> T (a,b)

其中T是我可以遍历的某种容器。此函数基本上重新排列a周围,不会创建新的,或删除任何内容。

我似乎已经陷入了在f的{​​{1}}部分运行a的最惯用的方式,并在最后附上[(a,b)]

我想在最后使用b来简单地进行查找,但是我想知道是否有更好的方法来做我正在做的事情,不知怎的“沿线”{{1}与其余的计算一起。

如果没有,你能解释一下原因吗?

显而易见的另一种方法是重写Data.Map但我不希望这样,因为b并不关心f

非常感谢您的帮助。

4 个答案:

答案 0 :(得分:7)

您的类型b是“只是额外信息”让我想起Env comonad,它是最简单的comonad之一,可用于将有用的额外信息附加到值。

import Control.Comonad
import Control.Comonad.Env

toenv :: [(a,b)] -> [Env b a]
toenv = map (\(a,b)->env b a)

也许您可以重写类型为[a] -> [a]的函数,以使用更通用的类型Comonad w => [w a] -> [w a],在comonad中使用多态。如果你必须生成新值,那将是一个问题(comonads不提供将值放在comonadic上下文中的一般方法),但由于你只想重新排序现有值(或删除它们),它可以正常工作。 / p>

请注意,您始终可以使用extract函数从a获取w a值。

要从广义的[a] -> [a]函数中恢复原始import Control.Comonad.Identity simplify :: Functor f => (forall w. Comonad w => f (w a) -> f (w a)) -> f a -> f a simplify f = fmap extract . f . fmap Identity 函数,只需使用Identity comonad。

{{1}}

答案 1 :(得分:1)

让我们说你有一个

rearrange :: [a] -> [a]

但你想重新排列像[(a,b)]这样的列表。

你只需将重新排列重写为

rearrangeBy :: (c -> a) -> [c] -> [c]

用检查位置上的(f x)替换元素x的出现次数

然后重写你的目标函数,传递新的

targetfun :: ((c -> a) -> [c] -> [c]) -> [(a,b)] -> [(a,b)]
targetfun rearrangeBy pairList = rearrangeBy fst pairList

答案 2 :(得分:1)

该功能可以像这样实现:

  1. 从该关联列表中提取关键列表
  2. 将“重新排列”功能应用于此密钥列表以获取新密钥列表(可能嵌入容器中)
  3. 将新密钥列表中的每个密钥映射到原始关联列表中的相应对
  4. 以上描述可以直接翻译成Haskell代码:

    generalArrange :: (Functor f, Eq a, Show a) => [(a, b)] -> ([a] -> f a) -> f (a, b)
    generalArrange al f = fmap keyToPair $ f as
        where as = map fst al
              keyToPair k = lookup k al
              lookup k [] = error $ "Invalid key: " ++ show k
              lookup k (a:as)
                | k == fst a = a
                | otherwise = lookup k as
    

    测试:

    ghc > let al = [(2, "def"), (1, "abc"), (3, "ijk")]
    ghc > generalArrange al sort
    [(1,"abc"),(2,"def"),(3,"ijk")]
    

答案 3 :(得分:0)

没有办法沿着" [a] -> T a函数中另一种类型的值。一旦应用了这一点,您就需要某种方式为每个b查找相应的a。我认为你对Map的想法是关于你可以做的最好而不重写f。取决于aHashMapIntMap可能会在您的具体情况下更好地发挥作用。