如何优雅地创建可选值列表?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何优雅地创建可选值列表?相关的知识,希望对你有一定的参考价值。

考虑以下功能

annotate :: AST -> [MetaInfo]
annotate (ArgDecl name nameReq maybeVal) 
    = concat [
      [m [Name] name],
      if nameReq
        then [m [Operator] "!"]]
        else [],
      case maybeVal of
                      Just v  -> [annotate v]
                      Nothing -> []
    ]
...

这看起来很优雅。有没有比使用concat和空列表更好的方法来创建可能存在或不存在的值列表?

答案

正如@AJFarmar所说,只是清理它会有所帮助:

annotate :: AST -> [MetaInfo]
annotate (ArgDecl name nameReq maybeVal)
  = concat
    [ [m [Name] name]
    , if nameReq
        then [m [Operator] "!"]
        else []
    , case maybeVal of
        Just v -> [annotate1 v]
        Nothing -> []
    ]

catMaybesData.Maybe的帮助下,也可以更清楚地从singleton / empty-set切换到Just / Nothing:

annotate' :: AST -> [MetaInfo]
annotate' (ArgDecl name nameReq maybeVal)
  = catMaybes
    [ Just (m [Name] name)
    , if nameReq
        then Just (m [Operator] "!")
        else Nothing
    , annotate1 <$> maybeVal
    ]

最后,如果您更喜欢这种语法,可以考虑创建一些辅助函数并使用<>

annotate'' :: AST -> [MetaInfo]
annotate'' (ArgDecl name nameReq maybeVal)
  =    always (m [Name] name)
    <> whenever nameReq (m [Operator] "!")
    <> sometimes (annotate1 <$> maybeVal)

有助手:

always :: a -> [a]
always = (:[])
sometimes :: Maybe a -> [a]
sometimes = maybeToList
whenever :: Bool -> a -> [a]
whenever b a = if b then [a] else []
另一答案

当我最终得到像这样的粗略代码时,我通常会通过命名碎片来清理它:

annotate :: AST -> [MetaInfo]
annotate (ArgDecl name nameReq maybeVal) 
    = concat [name, bang, annotation]
    where
        name = [m [Name] name]

        bang | nameReq = [m [Operator] "!"]]
             | otherwise = []

        annotation = case maybeVal of
          Just v  -> [annotate v]
          Nothing -> []

考虑到你有一个Maybe,我可能会去catMaybes简化annotation定义:

annotate :: AST -> [MetaInfo]
annotate (ArgDecl name nameReq maybeVal) 
    = catMaybes [name, bang, annotation]
    where
        name = Just $ m [Name] name

        bang | nameReq = Just $ m [Operator] "!"
             | otherwise = Nothing

        annotation = annotate <$> maybeVal
另一答案

我倾向于将列表推广到任何Alternative,并利用相关的函数。在这种情况下,我发现guard condition *> ...非常好。

annotate :: Alternative f => AST -> f MetaInfo
annotate (ArgDecl name nameReq maybeVal) =
   pure (m [Name] name)
   <|>
   guard nameReq *> pure (m [Operator] "!")
   <|>
   maybe empty (pure . annotate) maybeVal

或者,即使使用普通列表,使用列表推导看起来也不错。

annotate :: AST -> [MetaInfo]
annotate (ArgDecl name nameReq maybeVal) =
   [m [Name] name]
   ++
   [ m [Operator] "!" | nameReq ]
   ++
   [ annotate v | Just v <- maybeVal ]

以上是关于如何优雅地创建可选值列表?的主要内容,如果未能解决你的问题,请参考以下文章

UIControl子类-意外地找到nil,同时隐式展开一个可选值

如何在spring EL中将null作为可选值传递?

不能对“ViewController”类型的非可选值使用可选链接

快速致命错误:在展开可选值时意外发现 nil

向后传递数据时,在展开可选值时意外发现 nil

在打开可选值图像时意外地发现了nil