Haskell函数保护如何在函数参数之外的其他值上运行?

时间:2013-07-15 09:27:44

标签: haskell

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

那么有人可以解释这背后的魔力吗?

这可以改写成更容易理解的形式吗?

2 个答案:

答案 0 :(得分:9)

您可以将警卫视为if语句的语法糖。 guard中的表达式可以是任何有效的布尔表达式,就像在if语句中一样。这意味着您可以使用范围内的任何值和函数。

例如,您可以重写以下内容:

foo x | abc = ...
      | def = ...
      | otherwise = ...

as

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来编写所有内容,可以更容易地看到不同的特征对于同一事物而言只是语法糖。

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

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

我们可以想象将其重写如下:

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

作为

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

您可以看到此版本与case版本的普通警卫之间的平行关系。模式守卫只是将desugaring延伸到任意模式而不仅仅是布尔值。

同样,我相信你会同意在case语句中允许任何表达式是有意义的 - 没有理由将它限制为使用函数的参数。对于守卫来说也是如此,因为他们真的只是语法糖。

答案 1 :(得分:5)

这称为模式保护 - 阅读here

相当于

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)