2011-05-17 58 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