一個簡單的方法是定義一個數據類型的鏈接,即
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
是有可能有一個映射,其關鍵字是另一個數據類型? (你會爲其提供數據構造函數Haskell,Reddit和Ord的一個實例)這是否會導致其他問題? – Ptival 2011-05-17 09:28:25
也許'實例枚舉URL哪裏...'幫助? – phynfo 2011-05-17 12:37:39