繁体   English   中英

如何解决此代码异味?

[英]How do I fix this code smell?

我有一些代码执行显式递归,最重要的是,它在不需要时两次调用同一函数。 我认为我可以修复后者,但在前者方面需要帮助。

yesodIdentifier :: Text -> [LDAPEntry] -> Text
yesodIdentifier name ((LDAPEntry _ attributes):_) =
  let (Just eMail) = L.lookup "proxyAddresses" attributes
      partedEmail = L.map (S.splitOn "@") eMail -- now we have   
                                                -- [["garbage:name","domain"]]
  in yesodIdentifier' name partedEmail -- the secondary function is the problem

     where yesodIdentifier' :: Text -> [[String]] -> Text
           yesodIdentifier' nameToMatch ((name:[domain]):rest) =
             if ((unpack nameToMatch) == (sanitized name))
              then (pack (sanitized name)) `append`
                   (pack "@") `append`
                   (pack domain)
              else yesodIdentifier' nameToMatch rest
             where sanitized :: String -> String
                   sanitized dirty =
                     let (garbage:[cleanedName]) = S.splitOn ":" dirty
                     in cleanedName
           yesodIdentifier' name _ = pack "empty identifier"

我想做的是从LDAPEntry中获取(String,[String]),并将其缩减为与给定名称匹配的电子邮件地址。

您可以看到递归在哪里。 如果可以解决此问题,则无需担心yesodIdentifier' name _ = pack "empty identifier"因为如果用户不在LDAP数据库中,则根本不会调用此代码。 我只是把它放在那里完成。 我认为这可以更好地表现为折痕,但我无法完全正确地表达出来。 有任何想法吗?

这可以表示为过滤器。 这并非易事,因为如果您进行递归,那么您将在休息时递归并丢弃较早的条目。 您仍然必须处理空列表:

yesodI nameToMatch list = let result = filter (match(unpack nameToMatch)) list
                              match s1 (s2:[domain]) = s1 == s2
                          in case result of 
                             [] -> "empty identifier"
                             res  -> repack (head res)

repack arg@(name:[domain]) = (pack (sanitized name)) `append`
                   (pack "@") `append`
                   (pack domain)

来自ja的答案,重写为使用find:

yesodI name l = intercalate "@" <$> (find ((name ==) . head) $ filter (not . null) l)

更具可读性的版本

yesodI name list = repack <$> find matchName list'
 where list' = filter (not . null) list
       repack = intercalate "@"
       matchName = (name ==) . head

您可以消毒的电子邮件地址(name, domain)第一对,使用find找到的第一个具有匹配的名称,然后maybe来决定,如果你做什么做/ DO-找不到匹配:

yesodIdentifier :: Text -> [LDAPEntry] -> Text
yesodIdentifier name ((LDAPEntry _ attributes):_) =
  let (Just eMail) = L.lookup "proxyAddresses" attributes
      name' = T.unpack name
      sanitizedEmail = concatMap sanitize eMail -- now we have [("name","domain")]
      empty = "empty identifier"
      nonEmpty (name, domain) = concat [name, "@", domain]
      sanitize s = do
        (dirtyName:[domain]) <- [S.splitOn "@" s]
        (garbage:[cleanedName]) <- [S.splitOn ":" dirtyName]
        return (cleanedName, domain)
  in T.pack . maybe empty nonEmpty . L.find ((name' ==).fst) $ sanitizedEmail

这是未经测试的,因为我还没有所有可用的类型...我希望这能引起您的santize ,在List Monad中将丢弃无法分解为garbage:name@domain邮件的电子邮件地址garbage:name@domain

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM