列表与映射(关键安全性与映射所有元素)

发布于 2024-11-07 21:12:43 字数 416 浏览 0 评论 0原文

以下场景的最佳数据结构是什么?

假设您有一个 URL 列表

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

,并且单独使用它们,但您还想对所有这些 URL 进行操作,例如链接检查,您可以将它们放在列表中

allLinks = [
    linkHaskell
  , linkReddit
  ...
  ]

但这很容易出错,因为您可能会忘记添加一个新链接。

您可以选择将这些 URL 存储在 Map 中,但随后您会将编译时错误替换为运行时错误,以防键中存在拼写错误。

在 Haskell 中你会做什么?

What is the best data structure for the following scenario?

Say, you have a list of URLs

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

and you use them individually, but you also want to operate on all of them, e.g. link-check, you could put them in a list

allLinks = [
    linkHaskell
  , linkReddit
  ...
  ]

But that is error-prone, since you might forget to add a new link.

You could choose to store those URLs in a Map instead, but then you would exchange compile-time errors for runtime-errors, in case you have typos in the keys.

In Haskell what would you do?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

寄与心 2024-11-14 21:12:43

一种简单的方法是为链接定义一种数据类型,即

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 ),编译器会抱怨)。

另一种方法是使用一些 Template 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" ++)

现在您只需在一个位置指定链接:

{-# 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

One simple approach is to define a datatype for the links, i.e.

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]

You still have to specify the name in two places, but at least now the compiler will complain if you forget to add it in one place (at least with -Wall).

Another approach is to use some Template Haskell magic:

{-# 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" ++)

Now you only have to specify the links in one place:

{-# 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文