我的讲师目前有一种我以前从未见过的奇怪习惯,我想知道这是一个Haskell标准还是他编程风格的怪癖。
基本上,他经常做这样的事情:
functionEx :: String -> Int
functionEx s = functionExA s 0
functionExA :: String -> Int -> Int
functionExA s n = --function code
他称这些'辅助'函数,并且在大多数情况下,我可以看到的唯一优点是使用较少的提供参数来调用函数。但是大多数这些都隐藏在代码中,在我看来,在原始调用中添加参数更具可读性。
正如我所说,我并不是说我的观点是正确的,我之前没有看到过这样做,并且想知道它是否在Haskell中很常见。
答案 0 :(得分:5)
是的,这很常见,而且不仅仅是在函数式编程中。在代码中将接口与代码分开是很好的做法(在这种情况下,这意味着函数签名:您必须传递的参数)来自实现的细节(需要在递归代码中使用计数器或类似代码)
在实际编程中,一种表现形式是具有默认参数或一个函数的多次重载。另一种常见的方法是返回或获取接口的实例,而不是实现该接口的特定类。在Java中,这可能意味着从方法而不是List
返回ArrayList
,即使您知道代码实际使用了ArrayList
(其中ArrayList
实现了List
1}}接口)。在Haskell中,类型类通常具有相同的功能。
“一开始应该为零的一个参数”模式偶尔发生在现实世界中,但它在函数式编程教学中尤为常见,因为你想要展示如何在递归样式中编写相同的函数。尾递归。包装函数对于证明两个实现实际上具有相同的结果也很重要。
在Haskell中,使用where
更为常见,如下所示:
functionEx :: String -> Int
functionEx s = functionExA s 0 where
functionExA s n = --function code
这样,即使存在“真实”功能也会从外部接口隐藏。没有理由公开这个函数(比如说)使用count参数进行尾递归这一事实。
答案 1 :(得分:2)
如果经常使用特殊情况定义,则执行此操作可能是有利的。例如,sum函数只是fold函数的一个特例。那么为什么我们不是每次只使用 if UIApplication.shared.canOpenURL(url){
print("Can open shared application url.")
if #available(tvOS 10.0, *) {
print("tvOS 10.0 detected")
UIApplication.shared.open(url){res in
//res is false...
print("Result..." + String(res))
}
} else {
// Fallback on earlier versions
UIApplication.shared.openURL(url)
}
}
而不是foldr (+) 0 [1, 2, 3]
?因为sum [1,2,3]
更具可读性。