首页 > 解决方案 > 如何跨模式匹配执行 where 子句

问题描述

我可以让一个where子句在模式匹配case语句中起作用:

updateHung :: Text -> Maybe Char -> Int
updateHung word got =
    let x = case got of
            Just l
                | elem l . unpack $ word -> pass
                | otherwise -> strike
            Nothing -> pass
            where
                strike = 1
                pass = 0
    in x

但是当我尝试使用 multipart 函数做同样的事情时它不起作用:

updateHung :: Text -> Maybe Char -> Int
updateHung word (Just l)
    | elem l . unpack $ word = pass
    | otherwise = strike
updateHung word Nothing = pass
    where
        strike = 1
        pass = 0

有什么方法可以让它工作吗?

标签: haskell

解决方案


在工作版本中,您的where子句被误导性缩进。您已将其缩进,就好像它附加到case语句中一样,但实际上它附加到 , 的定义中x,并且会更清楚地缩进为

updateHung :: Text -> Maybe Char -> Int
updateHung word got =
    let x = case got of
          Just l
              | elem l . unpack $ word -> pass
              | otherwise -> strike
          Nothing -> pass
          where
            strike = 1
            pass = 0
    in x

一个where子句的范围总是限定为单个模式,跨越该模式的所有守卫。这非常重要,因为这允许它使用由模式引入的变量。例如,l在 的定义中使用它可能对您有用,但如果您能以某种方式将其范围限定为整个语句pass,那将毫无意义。case

如果您希望所有模式的变量都在范围内,则必须在开始模式匹配之前绑定这些变量。为您的函数定义一个方程,并在其中定义变量,无论是 withlet还是 with where,然后在case所有参数的元组上执行其余的逻辑,或者只是您关心的参数:

updateHung :: a -> Maybe Char -> Int
updateHung word got =
  let strike = 1
      pass = 0
  in case got of
     Just l
       | elem l . unpack $ word -> pass
       | otherwise -> strike
     Nothing -> pass

或者

updateHung :: Text -> Maybe Char -> Int
updateHung word got =
  case got of
     Just l
       | elem l . unpack $ word -> pass
       | otherwise -> strike
     Nothing -> pass
  where strike = 1
        pass = 0

推荐阅读