Len*_*low 6 haskell data-structures
以下场景的最佳数据结构是什么?
比如,你有一个URL列表
linkHaskell = Url "http://www.haskell.org"
linkReddit = Url "http://www.reddit.com"
...
Run Code Online (Sandbox Code Playgroud)
并且你单独使用它们,但是你也希望对它们进行操作,例如链接检查,你可以把它们放在一个列表中
allLinks = [
linkHaskell
, linkReddit
...
]
Run Code Online (Sandbox Code Playgroud)
但这很容易出错,因为您可能忘记添加新链接.
您可以选择将这些URL存储在Map中,但是如果您在键中存在拼写错误,则会为运行时错误交换编译时错误.
在Haskell你会做什么?
一种简单的方法是为链接定义数据类型,即
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]
Run Code Online (Sandbox Code Playgroud)
你仍然需要在两个地方指定名称,但至少现在如果忘记将它添加到一个地方(至少有-Wall),编译器会抱怨.
另一种方法是使用一些模板Haskell魔术:
{-# 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" ++)
Run Code Online (Sandbox Code Playgroud)
现在您只需在一个地方指定链接:
{-# 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
Run Code Online (Sandbox Code Playgroud)