在http://lisperati.com/haskell/ht4.html上,作者显示了从简单的SVG文件中读取多边形的函数.我理解大部分代码,但我想知道是否可以重写该函数
  let readPoint :: String -> Point
      readPoint s | Just [x,y] <- matchRegex (mkRegex "([0-9.]+),([0-9.]+)") s = (read x,read y)
以更易理解的形式.我发现这条线有点令人困惑,因为守卫应该对函数的参数进行操作(在本例中为"readPoint"),但是这里的守卫显然是对matchRegex的结果进行操作.
所以有人可以解释这背后的魔力吗?
这可以改写成更容易理解的形式吗?
您可以将警卫视为if语句的语法糖.guard中的表达式可以是任何有效的布尔表达式,就像在if语句中一样.这意味着您可以使用范围中的任何值和函数.
例如,您可以重写以下内容:
foo x | abc = ...
      | def = ...
      | otherwise = ...
如
foo x = if abc then ... else if def then ... else ...
我们也可以更详细地写这个case而不是if:
foo x = case abc of
  True -> ...
  False -> case def of
    True -> ...
    False -> ...
毕竟,if本身只是一个案例的语法糖!用一些方式编写所有内容case可以更容易地看到不同的功能如何只是同一件事的语法糖.
即使条件引用现有变量(abc和def)而不是函数参数x,第二个表达式仍然有意义; 警卫只是以同样的方式工作.
你的例子有点复杂,因为它使用了一个名为"模式守卫"的扩展.这意味着守卫不仅仅是一个布尔值 - 它还可以尝试匹配一个模式.如果模式匹配,则后卫成功(例如,与后卫相同True); 否则,后卫无法匹配(就像获得False).
我们可以想象将其重写如下:
readPoint s | Just [x, y] <- matchRegex (mkRegex "...") s = ...
            | otherwise = ...
如
readPoint s = case matchRegex (mkRegex "...") s of
                Just [x, y] -> ...
                _ -> ...
您可以看到此case版本和普通警卫版本之间的平行关系.模式守卫只是将desugaring延伸到任意模式而不仅仅是布尔.
同样,我相信你会同意在语句中允许任何表达式是有意义的case- 没有理由将它限制为使用函数的参数.卫兵也是如此,因为他们真的只是语法糖.
这被称为模式保护 - 在这里阅读它.
它相当于
readPoint :: String -> Point
readPoint s = case matchRegex (mkRegex "([0-9.]+),([0-9.]+)") s of
                   Just [x,y] -> (read x,read y) 
这个想法是你可以摆脱讨厌的嵌套case语句.使用图案防护你可以做类似的事情
readPoint :: String -> Point
readPoint s | Just [x,y] <- matchRegex (mkRegex "([0-9.]+),([0-9.]+)") s = (read x,read y)
            | Just [x] <- matchRegex (mkRegex "([0-9.]+)") s = (read x,0)
            | otherwise = (0,0)
替换更冗长的
readPoint :: String -> Point
readPoint s  = case matchRegex (mkRegex "([0-9.]+),([0-9.]+)") s  of 
                    Just [x,y] -> (read x,read y)
                    Nothing -> case matchRegex (mkRegex "([0-9.]+)") s of
                                    Just [x] -> (read x,0)
                                        Nothing -> (0,0)