這是從我的這個問題的解決方案延伸出來的
data CoroMap a = CoroMap (ColorMap (RoleMap a))
instance Functor CoroMap where
fmap fn (CoroMap coro) =
CoroMap $ fmap (fmap fn) coro
visions:: Piese -> [Vision]
visions p = [] 。
ihavethis :: CoroMap [Piese]
ineedthis:: CoroMap [Vision]
-- ineedthis =??
--我有這個a -> [b]
-- 我需要這個 [a] -> [b]
--專門將CoroMap [Piese] 轉換為CoroMap [Vision]
--使用Piese -> [Vision]
uj5u.com熱心網友回復:
我有這個a -> [b]
我需要這個 [a] -> [b]
在Haskell中,很多類似的問題基本上可以歸結為 "遵循型別"--意思是(有時,雖然不總是)你不需要過多地考慮你實際上希望函式做什么,你只需要型別相匹配。(這可能看起來很神奇,在某種程度上也是如此--這是因為與許多其他靜態型別的語言相比,Haskell中的型別給了你很多資訊)。) 而選擇一個具有正確型別的函式的能力往往只需要一點點的經驗。
即使你沒有太多的經驗,也有一個非常好的方法來 "作弊"--去Google并輸入你感興趣的型別簽名。在這里,輸入
(a -> [b]) -> [a] -> [b)
讓它搜索會出現很多相關的結果,其中第一個就是concatMap。這是一個函式,給定一個型別為a -> [b]的函式和一個型別為[a]的串列,首先將該函式映射到串列上,產生一個串列([[b]]),然后將這些串列串聯起來,得到一個簡單的[b]。這很可能就是你想要的(根據你對我的建議的回應,似乎也是如此)。
在不需要像Hoogle這樣的助手就能發現這個問題方面--單體在Haskell中無處不在,而串列是形成單體的許多非常常見的型別之一。因此,看到你有一個a -> m b(對于一個特定的單體m),并且想要一個m a -> m b,任何有一點經驗的Haskeller都會立刻想到Monad型別的基本方法,即(>>=)(讀作 "bind"),并且有型別
(Monad m) => m a -> (a -> m b) -> m b
這與你想要的非常接近,唯一的區別是你必須翻轉它,以獲得:
這與你想要的非常接近。
flip (>>=) :: (Monad m) => (a -> m b) -> m a -> m b
由于currying(又稱 "型別簽名中的箭頭是右聯的"),這與
相同flip (>>=) :: (Monad m) => (a -> m b) -> (m a -> m b)
這正是你所要求的,只是它將對所有單體起作用,而不僅僅是串列。這就是我想出concatMap的原因,因為對于串列的(>>=)被定義為flip concatMap,所以你想要的flip (>>=)就是concatMap。
還要注意的是,我在上面提到的Hoogle搜索中列出了(=<<),這只是flip(>>=)的縮寫。因此,這一切都很好地結合在一起。
最后,對于你的獎勵問題:
我需要這個函式
f [a] -> (a -> [b]) -> f [b]/code>
從背景關系來看,f是一個Functor - 這只是一個結合我們已經擁有的東西的例子:
concatMap :: (a -> [b]) -> ([a] -> [b])`。
用fmap。鑒于g :: a -> [b]我們知道concatMap g是[a] -> [b]型別,所以fmap (concatMap g)是f [a] -> f [b]型別。換句話說,g -> fmap (concatMap g) (你也可以寫成fmap . concatMap)具有(a -> [b]) -> f [a] -> f [b]的型別,所以我們只需要應用互換引數。所以你要的函式是
flip (fmap . concatMap)
以無點形式,或者如果你喜歡顯式引數(看起來不那么優雅,但通常更容易理解),你可以寫成
as g -> fmap (concatMap g) as
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/316919.html
標籤:
上一篇:如何驗證一個創建多個記錄的表單
