@Zeta 的回答很有趣。但是如果你像我一样是 Haskell 的新手,你可能想要一个“简单”的答案开始。 (只是为了获得基本的递归模式......并理解缩进,以及类似的事情。)
我不会将任何内容除以 2,我将包括数字本身。所以factorlist 15 => [1,3,5,15]在我的例子中:
factorList :: Int -> [Int]
factorList value = factorsGreaterOrEqual 1
where
factorsGreaterOrEqual test
| (test == value) = [value]
| (value `mod` test == 0) = test : restOfFactors
| otherwise = restOfFactors
where restOfFactors = factorsGreaterOrEqual (test + 1)
第一行是类型签名,你已经知道了。类型签名doesn't have to live right next to the list of pattern definitions for a function,(尽管模式本身需要在连续的行上全部在一起)。
然后factorList 是根据辅助函数定义的。这个辅助函数在where 子句中定义...这意味着它是本地的并且可以访问值参数。如果我们在全局范围内定义 factorGreaterOrEqual,那么它需要两个参数,因为 value 不在范围内,例如
factorsGreaterOrEqual 4 15 => [5,15]
您可能会争辩说,factorsGreaterOrEqual 本身就是一个有用的函数。也许是,也许不是。但在这种情况下,我们要说它除了帮助我们定义 factorList...之外没有什么用处,所以使用 where 子句并隐式获取值更简洁。
Haskell 的缩进规则(在我看来)很奇怪,但是 here they are summarized。我在这里缩进了两个空格,因为如果你使用 4,它会增长得太远。
在 Haskell 中,前面带有管道字符的布尔测试列表称为“守卫”。我只是将终止条件确定为测试达到值时;所以factorsGreaterOrEqual N = [N],如果我们打电话给factorList N。然后我们通过该值除以它是否没有余数来决定是否将测试编号连接到列表中。 (otherwise 是一个 Haskell 关键字,有点像 C 类 switch 语句中的 default 用于失败的情况)
为了展示另一个层次的嵌套和另一个隐式参数演示,我添加了一个 where 子句来在本地定义一个名为 restOfFactors 的函数。无需将 test 作为参数传递给 restOfFactors,因为它存在于 factorsGreaterOrEqual 的“范围内”......并且因为它存在于 factorList 的范围内,所以 value 也是可用的。