函数定义与守卫

4

定义Haskell函数的一种经典方式是:

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

我有点不满意每行都写函数名。现在我通常使用模式匹配扩展来编写以下方式,认为这更易读且更易修改:

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

您认为第二个示例更易读、易修改和优雅吗?生成的代码呢?(抱歉,还没有时间查看去糖化输出!)缺点是什么?我唯一看到的就是扩展使用。


1
f2 中,您需要为每个模式重复 <- s 部分。这取决于您的喜好。 - is7s
所以我会使用老派的写法 :) 它有一个缺点:它不能匹配多个参数:f 0 _ = []; f _ [] = []; f n (x:xs) = f (n-1) xs - demi
2个回答

8

嗯,你总是可以这样写:

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

这意味着与f1版本相同。如果函数名称很长或难以阅读,并且您想匹配许多模式,则这可能会有所改善。对于您在此处的示例,我将使用常规语法。
你的f2版本没有问题,但似乎是一种轻浮的用法,它不常见,不能假定每个人都熟悉它。对于个人代码来说并不是什么大问题,但对于您希望其他人阅读的内容,我建议使用case表达式。

6
我喜欢在模式匹配时写函数名,就像您的情况所示。我发现这样更易读。
当函数参数有些条件时,我倾向于使用guards,这有助于避免使用if else语句,如果我按照第一种模式,则不得不使用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(你可能不认为这是什么大问题)

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接