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
都与a
b
相关联

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