我有一个关联列表
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
。
非常感谢您的帮助。
答案 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)
该功能可以像这样实现:
以上描述可以直接翻译成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
。取决于a
,HashMap
或IntMap
可能会在您的具体情况下更好地发挥作用。