代码之家  ›  专栏  ›  技术社区  ›  RasmusWL

在保护中使用一元布尔值?(图案防护)

  •  4
  • RasmusWL  · 技术社区  · 10 年前

    我刚发现 PatternGuards 语言扩展,看起来很不错。

    我所处的情况是,我希望模式匹配出一个值,对该值应用一个一元布尔函数,并且只在结果为 False 。否则,我想执行默认操作(可能不像下面列出的那样简单)。

    这可以通过使用 if 在进行模式匹配之后,但我宁愿不复制默认操作的代码,或者在单独的函数中删除该代码(即保持防护的穿透行为)

    有没有办法做到这一点 没有 这个 如果 ?

    {-# LANGUAGE GeneralizedNewtypeDeriving, PatternGuards #-}
    
    import Control.Applicative
    import Control.Monad.State
    
    newtype MyM a = MyM (StateT Int (Either String) a)
                    deriving ( MonadState Int
                             , Monad, Applicative, Functor
                             )
    
    --------------------------------------------------------------------------------
    
    foo :: Int -> MyM Bool
    foo = undefined
    
    bar :: Either a Int -> MyM Int
    bar (Right n)
      | ok <- foo n, ok == False = return 42
    bar _ = return 0
    

    以上代码给出错误消息

    Couldn't match expected type ‘MyM Bool’ with actual type ‘Bool’
    In the second argument of ‘(==)’, namely ‘False’
    In the expression: ok == False
    
    1 回复  |  直到 10 年前
        1
  •  3
  •   Petr    10 年前

    你所要求的是不可能的,而且有充分的理由。让我们这么说吧 foo 修改状态,但守卫中的条件不匹配。你将如何处理这种状态修改?模式与值是分开的,因此匹配模式不会导致结果改变。 你真的需要打电话 食品 在决定如何处理其输出的RHS中。

    在某些情况下,如果monad是可以匹配的数据类型,则可以执行以下操作

    foo :: Int -> Maybe Bool
    ...
    
    bar :: Either a Int -> MyM Int
    bar (Right n)
      | Just False <- foo n = ...
    

    但这仅仅是因为可以直接匹配monad的值。

    在某些情况下,扩展 lambda-case and multi-way if-expressions 可以让你的生活稍微轻松一些。