我正在尝试在Haskell中编写一个函数来计算除自身之外的给定数字的所有因子。
结果应如下所示:
factorlist 15 => [1,3,5]
我是Haskell和整个递归主题的新手,我很确定我已经在这个例子中申请了,但我不知道在哪里或如何。
我的想法是将给定数字与列表中从1到n div
2的第一个元素进行比较
使用mod
函数,但以某种方式递归,如果结果是0
,那么我在新列表中添加数字。 (我希望这很有意义)
我很感激有关此事的任何帮助
这是我的代码,直到现在:(它不起作用..但不知何故,以说明我的想法)
factorList :: Int -> [Int]
factorList n |n `mod` head [1..n`div`2] == 0 = x:[]
答案 0 :(得分:4)
有几种方法可以解决这个问题。但首先,让我们写一个小帮手:
isFactorOf :: Integral a => a -> a -> Bool
isFactorOf x n = n `mod` x == 0
这样我们就可以撰写12 `isFactorOf` 24
并获得True
或False
。对于递归部分,我们假设我们使用具有两个参数的函数:一个是我们想要分解的数字,第二个是我们当前正在测试的因子。我们只测试小于或等于n `div` 2
的因素,这导致:
createList n f | f <= n `div` 2 = if f `isFactorOf` n
then f : next
else next
| otherwise = []
where next = createList n (f + 1)
所以如果第二个参数是因子n
,我们将它添加到列表中并继续,否则我们继续。我们只在f <= n `div` 2
时执行此操作。现在,为了创建factorList
,我们只需使用createList
并使用足够的第二个参数:
factorList n = createList n 1
递归隐藏在createList
中。因此,createList
是worker,您可以将其隐藏在where
内的factorList
内。
请注意,可以使用过滤器或列表推导来轻松定义factorList
:
factorList' n = filter (`isFactorOf` n) [1 .. n `div` 2]
factorList'' n = [ x | x <- [1 .. n`div` 2], x `isFactorOf` n]
但在这种情况下,你自己也不会写出递归。
filter
功能。答案 1 :(得分:0)
@ 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
子句中定义...这意味着它是本地的,可以访问值参数。如果我们要全局定义factorsGreaterOrEqual,那么它将需要两个参数,因为值不在范围内,例如。
factorsGreaterOrEqual 4 15 => [5,15]
你可能会认为factorsGreaterOrEqual本身就是一个有用的函数。也许是,也许不是。但在这种情况下,除了帮助我们定义factorList
之外,我们还会说它不常用...所以使用where子句并隐含地获取值更清晰。
Haskell的缩进规则(对我的口味)很奇怪,但是here they are summarized。我在这里缩进两个空格,因为如果使用4,它会变得太大了。
在前面有一个带有该管道字符的布尔测试列表在Haskell中称为“警卫”。我只是将终端条件设置为测试达到值时;所以factorsGreaterOrEqual N = [N]
如果我们正在拨打factorList N
。然后我们决定是否将测试编号连接到列表中是否将值除以是否没有余数。 (otherwise
是一个Haskell关键字,与C-like switch语句中的default
有点类似
显示另一级嵌套和另一个隐式参数演示,我添加了一个where子句来本地定义一个名为restOfFactors
的函数。没有必要将test作为参数传递给restOfFactors,因为它生活在factorsGreaterOrEqual
的范围内......并且因为它位于factorList
的范围内,所以也可以使用值。 / p>