Functional Learning Issues

I am starting to work with functional languages, and I am trying to make it all happen in Haskell. Here's a quick-dirty function that finds all the factors of a number:

factors :: (Integral a) => a -> [a]
factors x = filter (\z -> x `mod` z == 0) [2..x `div` 2]

Works well, but I found it unbearably slow for large numbers. So I made myself better:

factorcalc :: (Integral a) => a -> a -> [a] -> [a]
factorcalc x y z
    | y `elem` z      = sort z
    | x `mod` y == 0  = factorcalc x (y+1) (z ++ [y] ++ [(x `div` y)])
    | otherwise       = factorcalc x (y+1) z

But here is my problem: even despite the fact that the code works and can literally shorten the hours from the execution time of my programs, this is disgusting!

It smells like ugly imperative thinking: it constantly updates the counter and data structure in the loop until it completes. Since you cannot change state in purely functional programming, I cheated by holding data in parameters that the function simply passes to itself again and again.

, , ...

+3
7

, , . , , . , , OQ. . "" ""!

:

  • - x - , .

  • , x; , x, ( ).

  • (factors) 2 n div 2, , . -O -ddump-simpl, GHC , .

  • factorcalc , , ; filter .

, - :

, x z 2:

factors_from x 1 = []
factors_from x z 
  | x `mod` z == 0 = z : factors_from x (z-1)
  | otherwise      =     factors_from x (z-1)

factors'' x = factors_from x (x `div` 2)

, , .

, :

factors_from' x 1 l = l
factors_from' x z l
  | x `mod` z == 0 = factors_from' x (z-1) (z:l)
  | otherwise      = factors_from' x (z-1) l

factors''' x = factors_from x (x `div` 2)

, factorcalc, 2 x div 2, factorcalc .

, factorcalc, , :

factors'''' x = sort $ uncurry (++) $ unzip $ takeWhile (uncurry (<=)) $ 
                [ (z, x `div` z) | z <- [2..x], x `mod` z == 0 ]

, 100 , , factorcalc , .

, : -)


: , , ( ):

saneFactors x = sort $ concat $ takeWhile small $
                [ pair z | z <- [2..], x `mod` z == 0 ]
    where pair z = if z * z == x then [z] else [z, x `div` z]
          small [z, z'] = z < z'
          small [z]     = True
+5

, . .

, ? ?

, ?

(.)

+4

-, factorcalc "", - factors' x = factorscalc x 2 [], .

"" factors , , . , factors n/2 , factorcalc sqrt n .

factors, sqrt n , . : (factor); x (small), (factorize):

factors' :: (Integral a) => a -> [a]
factors' x = sort (foldl factorize [] (takeWhile small (filter factor [2..])))
  where
    factor z = x `mod` z == 0
    small z = z <= (x `div` z)
    factorize acc z = z : (if z == y then acc else y : acc)
      where y = x `div` z

, factorscalc . factor factorize , factorscalc.

Real World Haskell GHC .

, nitpick factorscalc: O (1), n O (n). , , , , factorcalc - :

factorcalc :: (Integral a) => a -> a -> [a] -> [a]
factorcalc x y z
    | y `elem` z      = sort z
    | x `mod` y == 0  = factorcalc x (y+1) (y : (x `div` y) : z)
    | otherwise       = factorcalc x (y+1) z
+1

, , .

, ; , ! "" , .

- , . , , - , , " " ,. . , , :

sums :: Num a => [a] -> [a]
sums inp = helper inp []
    where
        helper []     acc       = reverse acc
        helper (x:xs) []        = helper xs [x]
        helper (x:xs) acc@(h:_) = helper xs (x+h : acc)

, , , ( ), .

, The Little Schemer, .

+1

, Haskell, . Norman factors'''' , , , .

factors :: Int -> [Int]
factors n = firstFactors ++ reverse [ n `div` i | i <- firstFactors ]
    where
    firstFactors = filter (\i -> n `mod` i == 0) (takeWhile ( \i -> i * i <= n ) [2..n])

, , sqrt n, , ( , , n - , , , , , div n i. , firstFactors, .

+1

Haskell, - , :

http://www.willamette.edu/~fruehr/haskell/evolution.html

: , . , ; , , , Haskell, , ; , . , OP, , -, , , .

0

"" . ( "" , , , , , Haskell.)

{-# LANGUAGE PatternGuards #-}
factors :: (Integral a) => a -> [a]
factors = multiplyFactors . primeFactors primes 0 [] . abs where
    multiplyFactors [] = [1]
    multiplyFactors ((p, n) : factors) =
        [ pn * x
        | pn <- take (succ n) $ iterate (* p) 1
        , x <- multiplyFactors factors ]
    primeFactors _ _ _ 0 = error "Can't factor 0"
    primeFactors (p:primes) n list x
        | (x', 0) <- x `divMod` p
        = primeFactors (p:primes) (succ n) list x'
    primeFactors _ 0 list 1 = list
    primeFactors (_:primes) 0 list x = primeFactors primes 0 list x
    primeFactors (p:primes) n list x
        = primeFactors primes 0 ((p, n) : list) x
    primes = sieve [2..]
    sieve (p:xs) = p : sieve [x | x <- xs, x `mod` p /= 0]

primes - . , .

   sieve [2..]
=> 2 : sieve [x | x <- [3..], x `mod` 2 /= 0]
=> 2 : 3 : sieve [x | x <- [4..], x `mod` 2 /= 0, x `mod` 3 /= 0]
=> 2 : 3 : sieve [x | x <- [5..], x `mod` 2 /= 0, x `mod` 3 /= 0]
=> 2 : 3 : 5 : ...

primeFactors - This is a simple repeated test division algorithm: it scans a list of primes and tries to divide a given number into each, writing down the factors as they progress.

   primeFactors (2:_) 0 [] 50
=> primeFactors (2:_) 1 [] 25
=> primeFactors (3:_) 0 [(2, 1)] 25
=> primeFactors (5:_) 0 [(2, 1)] 25
=> primeFactors (5:_) 1 [(2, 1)] 5
=> primeFactors (5:_) 2 [(2, 1)] 1
=> primeFactors _ 0 [(5, 2), (2, 1)] 1
=> [(5, 2), (2, 1)]

multiplyPrimes takes a list of primes and degrees and explodes it to a complete list of factors.

   multiplyPrimes [(5, 2), (2, 1)]
=> [ pn * x
   | pn <- take (succ 2) $ iterate (* 5) 1
   , x <- multiplyPrimes [(2, 1)] ]
=> [ pn * x | pn <- [1, 5, 25], x <- [1, 2] ]
=> [1, 2, 5, 10, 25, 50]

factorsjust connects the two functions together with absto prevent infinite recursion if the input is negative.

0
source

Source: https://habr.com/ru/post/1708612/


All Articles