假設我有一些非常簡單的代碼:
import qualified Data.Map as Map
import Data.Maybe(fromJust)
keySum :: Map.Map Char Int -> Char -> Char -> Either String Int
keySum m key1 key2
| val1 == Nothing = Left $ show val1 " not in map"
| val2 == Nothing = Left $ show val2 " not in map"
| otherwise = Right $ val1' val2'
where
val1 = Map.lookup key1 m
val2 = Map.lookup key2 m
val1' = fromJust val1
val2' = fromJust val2
當然,我不想使用fromJust, 而是希望對Map.lookuphere的結果進行模式匹配。
但是我怎樣才能做到這一點,而不需要評估Map.lookup兩次或通過一些包裝函式傳遞它呢?
uj5u.com熱心網友回復:
您可以使用模式保護:
keySum m key1 key2
| Just val1 <- Map.lookup key1 m
, Just val2 <- Map.lookup key2 m
= Right $ val1 val2
| key1 `Map.notMember` m
= Left $ show key1 " not in map"
| otherwise = Left $ show key2 " not in map"
但也許一個好的老人case實際上是更清潔的選擇:
keySum m k? k? = case (`Map.lookup` m) <$> [k?,k?] of
[Just v?, Just v?] -> Right $ v? v?
[Nothing, _ ] -> Left $ show k? " not in map"
_ -> Left $ show k? " not in map"
這可以通過觀察它只是一個標準的應用鏈來進一步簡化:
keySum m k? k? = ( ) <$> lku k? <*> lku k?
where lku k = case Map.lookup k m of
Just v -> Right v
Nothing -> Left $ show k " not in map"
如果你喜歡模式,也可以這樣寫(我個人不是這個擴展的粉絲):
{-# LANGUAGE ViewPatterns #-}
keySum m k? k? = ( ) <$> lku k? <*> lku k?
where lku ((`Map.lookup` m) -> Just v) = Right v
lku k = Left $ show k " not in map"
最后,沒有理由將其限制為只有兩個鍵,也可以對整個任意長度的串列進行排序。順便說一句,沒有理由選擇具體型別。
import Data.Traversable (forM)
keySum :: (Ord a, Show a, Num b) => Map.Map a b -> [a] -> Either String b
keySum m ks = sum <$> forM ks `id` \k -> case Map.lookup k m of
Just v -> Right v
Nothing -> Left $ show k " not in map"
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/359163.html
標籤:哈斯克尔
