我一直在嘗試通過做一些簡單的問題來學習haskell。
問題
目前,我正在嘗試實作一個函式primeFactorization :: Integer -> [(Integer, Integer)],使得輸出是一個包含素數因子的元組串列以及它在數字中的冪。
示例輸出
> primeFactorization 120
[(2,3), (3,1), (5,1)]因為 120 = 2^3 * 3^1 * 5^1
我的(部分)解決方案
primeFactorization :: Integer -> [Integer]
primeFactorization n =
let
factors :: Integer -> [Integer]
factors n = [x | x <- [2..n-1], n `mod` x == 0]
isPrime :: Integer -> Bool
isPrime n
| n `elem` [0, 1] = False
| n == 2 = True
| n > 2 = null [ x | x <- [2..(ceiling . sqrt . fromIntegral) n], n `mod` x == 0]
| otherwise = False
in
filter isPrime $ (factors n)
這是獲取數字的主要因素的有效實作。然而,正如所見,它只輸出主要因素。我不確定如何在haskell中存盤次數。另外,考慮到在haskell中迭代是不習慣的,我不知道我將如何實作該解決方案。在python中,我會這樣做:
def pf(number):
factors=[]
d=2
while(number>1):
while(number%d==0):
factors.append(d)
number=number/d
d =1
return factors
那么,問題來了:如何實作素因數的權力?
筆記:
- 我已經看到了:階乘的素數分解,但這并不能回答我的問題。
- 這不是作業問題,我正在獨立學習。
uj5u.com熱心網友回復:
您總是可以用遞回替換命令式語言回圈(只要它們不干預任何全域狀態)。這可能不是最優雅的方法,但在這種情況下,用遞回函式模仿你的內部 Python 回圈似乎非常合適:
dividerPower :: Integer -> Integer -> Int
dividerPower n d
| n`rem`d == 0 = 1 dividerPower (n`quot`d) d
| otherwise = 0
(與 Python 回圈相比,這算“向后”。您還可以使用輔助函式使其尾遞回并在累加器變數上向前計數,但這更尷尬,我認為不會有記憶體/性能優勢在這種情況下證明它是合理的。)
您可以將它與您的 Haskell 代碼一起使用(對于您已經找到的每個因素,檢查它發生的頻率),或者擴展它以便整個事情像 Python 解決方案一樣作業(實際上效率更高,因為它避免了每個數字檢查它是否是素數)。為此,您只需要n在結果中回傳最終結果。讓我們使用一個where塊來處理模式匹配,并制作remand:
dividePower :: Integer -> Integer -> (Integer, Int)
dividePower n d
| r == 0 = (nfin, p' 1)
| otherwise = (n, 0)
where (n', r) = n `quotRem` d
(nfin, p') = dividePower n' d
那么相當于你的Python代碼是
pf :: Integer -> Integer -> [(Integer, Int)]
pf = go 2
where go d n
| n>1 = (d, p) : go (d 1) n'
| otherwise = []
where (n', p) = dividePower n d
這實際上給了你,就像在 Python 中一樣,串列也包括非除法器(冪為 0)。為避免這種情況,請將串列構建更改為
| n>1 = (if p>0 then ((d,p):) else id) $ go (d 1) n'
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/498432.html
