[英]How to write a function of type a-> b -> b -> b for folding a tree
[英]How to write a function of type `[(a,b)] -> ([a] -> [a]) -> [(a,b)]`
我有一個關聯列表
L :: [(a,b)]
其中每個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
“只是額外的信息”讓我想起了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 => [wa] -> [wa]
,comonad中的多態。 如果你必須生成新的值,這將是一個問題(comonads不提供將值放在comonadic上下文中的一般方法),但由於你只想重新排序現有的值(或刪除它們),它將正常工作。
請記住,你可以隨時可以得到a
從值wa
使用extract
功能。
要從通用函數中恢復原始[a] -> [a]
函數,只需使用Identity
comonad。
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
假設你有一個
rearrange :: [a] -> [a]
但你想重新排列像[(a,b)]這樣的列表。
你只需重寫重新排列
rearrangeBy :: (c -> a) -> [c] -> [c]
在檢查位置上用(fx)代替元素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] -> T a
函數中無法“繞過”另一種類型的值。 一旦應用了,你將需要一些方法來查找每個a
的相應b
。 我認為你對Map
的想法是關於你可以做的最好而不重寫f
。 依賴於a
, HashMap
或IntMap
可能在您的特定情況下更好地工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.