2011-05-17 54 views
6

什麼是以下場景的最佳數據結構?列表與地圖(關鍵安全與所有元素的映射關係)

說,你有網址

linkHaskell = Url "http://www.haskell.org" 
linkReddit = Url "http://www.reddit.com" 
... 

的列表,你單獨使用它們,但你也想對所有的人,例如操作鏈接檢查,你可以把它們放在一個列表

allLinks = [ 
    linkHaskell 
    , linkReddit 
    ... 
    ] 

但是,這是容易出錯的,因爲你可能會忘記添加新的鏈接。

您可以選擇將這些URL存儲在Map中,但是如果在鍵中有拼寫錯誤,則會爲運行時錯誤交換編譯時錯誤。

在Haskell中你會做什麼?

+1

是有可能有一個映射,其關鍵字是另一個數據類型? (你會爲其提供數據構造函數Haskell,Reddit和Ord的一個實例)這是否會導致其他問題? – Ptival 2011-05-17 09:28:25

+0

也許'實例枚舉URL哪裏...'幫助? – phynfo 2011-05-17 12:37:39

回答

5

一個簡單的方法是定義一個數據類型的鏈接,即

data Link = LinkHaskell | LinkReddit 
    deriving (Enum, Bounded) 

toUrl LinkHaskell = Url "http://www.haskell.org" 
toUrl LinkReddit = Url "http://www.reddit.org" 

allLinks :: [Link] 
allLinks = [minBound .. maxBound] 

你仍然有兩個地方來指定名字,但至少現在,如果你忘了加上它的編譯器會抱怨一個地方(至少有-Wall)。

另一種方法是使用一些模板哈斯克爾法寶:

{-# LANGUAGE TemplateHaskell #-} 

module Links where 

import Control.Monad 
import Language.Haskell.TH 

data Url = Url String 
    deriving (Show) 

mkLinks :: [(String, String)] -> Q [Dec] 
mkLinks links = liftM2 (++) mkAllLinks $ mapM mkLink links 
    where 
    mkLink (name, url) = valD (varP $ mkLinkName name) (normalB [| Url url |]) [] 
    mkAllLinks = [d| allLinks = $(listE [varE $ mkLinkName name | (name, _) <- links])|] 
    mkLinkName = mkName . ("link" ++) 

現在你只需要指定一個地方的鏈接:

{-# LANGUAGE TemplateHaskell #-} 

import Links 

mkLinks 
    [("Haskell", "http://www.haskell.org") 
    ,("Reddit", "http://www.reddit.org") 
    ,("StackOverflow", "http://www.stackoverflow.com") 
    ] 

main = do 
    putStrLn "By name:" 
    print $ linkHaskell 
    print $ linkReddit 

    putStrLn "All:" 
    mapM_ print allLinks 
+0

有趣,謝謝。 – LennyStackOverflow 2011-05-18 07:52:35