Haskell 如何编写`[(a,b)]类型的函数->;([a]->;[a])->;[(a,b)]`
我有一份协会名单Haskell 如何编写`[(a,b)]类型的函数->;([a]->;[a])->;[(a,b)]`,haskell,Haskell,我有一份协会名单 L :: [(a,b)] 其中每个a都与ab相关联 b只是额外的信息,有趣的部分是a 我想使用a,因此我有一个类型为[a]->[a]的函数f。(在我的问题中,我实际上有[a]->[[a]]],所以如果你的答案可以推广到我可以遍历的任何容器,那就好了 我想我需要像这样的东西 [(a,b)] -> ([a] -> T a) -> T (a,b) 其中T是我可以遍历的某种容器)。这个函数基本上是重新排列a,它不创建新的,也不删除任何内容 在[(a,b)]的a部分
L :: [(a,b)]
其中每个a
都与ab
相关联
b
只是额外的信息,有趣的部分是a
我想使用a
,因此我有一个类型为[a]->[a]
的函数f
。(在我的问题中,我实际上有[a]->[[a]]]
,所以如果你的答案可以推广到我可以遍历的任何容器,那就好了
我想我需要像这样的东西
[(a,b)] -> ([a] -> T a) -> T (a,b)
其中T
是我可以遍历的某种容器)。这个函数基本上是重新排列a
,它不创建新的,也不删除任何内容
在[(a,b)]
的a
部分上运行f
最惯用的方式似乎是什么,最后将b
附加回去
我曾想过使用Data.Map
在末尾进行简单的查找,但我想知道是否有更好的方法来完成我所追求的任务,即在计算的其余部分中“遍历”b
如果没有,你能解释一下原因吗
另一个明显的方法是重写f
,但我不希望这样,因为f
不关心b
非常感谢您的帮助。您键入的
b
只是“额外信息”,这让我想起了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=>[wa]->[wa]
,即Comonad中的多态类型。如果您必须生成新的值,这将是一个问题(comonads不提供将值放入comonadic上下文中的一般方法),但由于您只想对现有值重新排序(或删除它们),因此它可以正常工作
请记住,始终可以使用函数从wa
获取a
值
要从通用函数恢复原始的[a]->[a]
函数,只需使用comonad
无法在[a]->ta
函数中“沿线程”另一类型的值。一旦应用了它,您将需要某种方法来查找每个a
对应的b
。我认为你关于地图的想法是你在不重写f
的情况下所能做的最好的。取决于a
,HashMap
或IntMap
可能在您的特定情况下工作得更好。假设您有一个
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
该功能可以这样实现:
从该关联列表中提取密钥列表
将“重排”功能应用于此密钥列表以获得新的密钥列表(可能嵌入到容器中)
将新密钥列表中的每个密钥映射到原始关联列表中对应的密钥对
上述描述可直接转换为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")]
所以类型为[a]->[a]
的函数不会更改列表的长度吗?不,我所做的只是重新排列列表elements@rafalio是否可以提供一个类型为a->Int
的函数,该函数给出元素a
的新索引?“在[(a,b)]
的a
部分运行f
最惯用的方法是什么,并在最后将b
附加回”,那么应该是:[(a,b)]->(a->a)->[(a,b)]
[a]->[a]
可以有各种语义,聚合、拆分、置换(你似乎在暗示什么),等等。你的问题不清楚,举个例子会有帮助。[(1,1),(2,2)]as[(a,b)],反其道而行之([a]->[a])给出[(2,1),(1,2)]或[(2,2),(1,1)]?谢谢,这可能是最简单的方法
ghc > let al = [(2, "def"), (1, "abc"), (3, "ijk")]
ghc > generalArrange al sort
[(1,"abc"),(2,"def"),(3,"ijk")]