10

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 的结果进行操作。

那么任何人都可以解释这背后的魔力吗?

可以将其重写为更易于理解的形式吗?

4

2 回答 2

10

您可以将守卫视为 if 语句的语法糖。守卫中的表达式可以是任何有效的布尔表达式,就像在 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可以更容易地了解不同的功能如何只是同一事物的语法糖。

即使条件引用现有变量 ( abcand def) 而不是函数参数,第二个表达式显然也有意义x;守卫只是以同样的方式工作。

你的例子有点复杂,因为它使用了一个名为"pattern guards"的扩展。这意味着守卫可以不仅仅是一个布尔值——它还可以尝试匹配一个模式。如果模式匹配,则守卫成功(例如,与带有 的守卫相同True);否则,守卫无法匹配(就像getting 一样False)。

我们可以想象将其重写为:

readPoint s | Just [x, y] <- matchRegex (mkRegex "...") s = ...
            | otherwise = ...

作为

readPoint s = case matchRegex (mkRegex "...") s of
                Just [x, y] -> ...
                _ -> ...

case您可以看到这与普通守卫版本之间的相似之处。模式守卫只是将脱糖扩展到任意模式,而不仅仅是布尔值。

同样,我相信您会同意在语句中允许任何表达式是有意义的case——没有理由将其限制为使用函数的参数。守卫也是如此,因为它们实际上只是语法糖。

于 2013-07-15T09:41:23.517 回答
6

这称为模式保护- 请在此处阅读有关它的信息。

相当于

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)
于 2013-07-15T09:41:03.037 回答