定义Haskell函数的经典方法是
f1 :: String -> Int
f1 ('-' : cs) -> f1 cs + 1
f1 _ = 0
我有点不满意在每一行写函数名。现在我通常用以下方式编写,使用模式保护扩展并认为它更易读和修改:
f2 :: String -> Int
f2 s
| '-' : cs <- s = f2 cs + 1
| otherwise = 0
你认为第二个例子更具可读性,可修改性和优雅性吗?生成代码怎么样? (还没有时间看到脱落的输出,对不起!)。什么是利弊?我唯一看到的是扩展用法。
答案 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(您可能不会考虑很多内容)
另一方面,对于函数参数的简单模式匹配,我将使用第一种方法,它简单易读。