带警卫的功能定义

时间:2012-09-13 13:34:45

标签: haskell

定义Haskell函数的经典方法是

f1 :: String -> Int
f1 ('-' : cs) -> f1 cs + 1
f1 _ = 0

我有点不满意在每一行写函数名。现在我通常用以下方式编写,使用模式保护扩展并认为它更易读和修改:

f2 :: String -> Int
f2 s
  | '-' : cs <- s = f2 cs + 1
  | otherwise = 0

你认为第二个例子更具可读性,可修改性和优雅性吗?生成代码怎么样? (还没有时间看到脱落的输出,对不起!)。什么是利弊?我唯一看到的是扩展用法。

2 个答案:

答案 0 :(得分:8)

好吧,你总是可以这样写:

f3 :: String -> Int
f3 s = case s of
           ('-' : cs) -> f3 cs + 1
           _          -> 0

这意味着与f1版本相同。如果该函数具有冗长或难以阅读的名称,并且您希望与大量模式匹配,则这可能是一种改进。对于您的示例,我将使用传统语法。

你的f2版本没有任何问题,但似乎有点轻率地使用了一种语法GHC扩展,这种扩展并不常见,以至于每个人都会熟悉它。对于个人代码而言,这并不是什么大不了的事,但我会坚持使用case表达式来表达您希望其他人阅读的内容。

答案 1 :(得分:6)

我喜欢在函数模式匹配时编写函数名称,如您的情况所示。我发现它更具可读性。

当我对函数参数有一些条件时,我更喜欢使用警卫,这有助于避免if else,如果我要遵循第一个模式,我将不得不使用它。

所以回答你的问题

Do you think that second example is more readable, modifiable and elegant?

不,我更喜欢第一个简单易读的。但或多或少取决于你的个人品味。

What about generated code?

我不认为生成的代码会有任何差异。两者都只是模式匹配。

What are cons? 

好的模板对模式匹配很有用,而不是使用let或更干净的东西。

addLookup env var1 var2
   | Just val1 <- lookup env var1
   , Just val2 <- lookup env var2
   = val1 + val2

当然,您需要使用扩展程序,而且它不是Haskell98(您可能不会考虑很多内容)

另一方面,对于函数参数的简单模式匹配,我将使用第一种方法,它简单易读。