Hi i'm pretty new to haskell and I want to make a program with prime numbers.
With the code below I put all the prime numbers between 2 integers in a list, now i want to make a sum of all the prime numbers of the generated list and show this as an answer.
primesR :: Integral a => a -> a -> [a]
primesR a b = takeWhile (<= b) $ dropWhile (< a) $ sieve [2..]
where sieve (n:ns) = n:sieve [ m | m <- ns, m `mod` n /= 0 ]
I didn't find any examples of the sum of a generated list. Does anyone know how I can manage this in the code?
thx
Just use the sum function, like so:
primesR :: Integral a => a -> a -> a
primesR a b = sum $ takeWhile (<= b) $ dropWhile (< a) $ sieve [2..]
where sieve (n:ns) = n:sieve [ m | m <- ns, m `mod` n /= 0 ]
Note that you need to change the function signature from Integral a => a -> a -> [a] to Integral a => a -> a -> a, since the result of summation is a single value, not a list.
Related
I am learning Haskell and am currently creating a program that finds all common divisors from 3 different Int:s.
I have a working program but the evaluation time is very long on big numbers. I want advice on how to optimize it.
EXAMPLE: combineDivisors 234944 246744 144456 == [1,2,4,8]
As said I am very new to this so any help is appreciated.
import Data.List
combineDivisors :: Int -> Int -> Int -> [Int]
combineDivisors n1 n2 n3 =
mergeSort list
where list = getTrips concList
concList = isDivisor n1 ++ isDivisor n2 ++ isDivisor n3
isDivisor n = [x | x <- [1..n], mod n x == 0]
getTriplets :: Ord a => [a] -> [a]
getTriplets = map head . filter (\l -> length l > 2) . group . sort
--Merge sort--
split :: [a] -> ([a],[a])
split xs =
let
l = length xs `div` 2
in
(take l xs, drop l xs)
merge :: [Int] -> [Int] -> [Int]
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys)
| y < x = y : merge (x:xs) ys
| otherwise = x : merge xs (y:ys)
mergeSort :: [Int] -> [Int]
mergeSort [] = []
mergeSort [x] = [x]
mergeSort xs =
let
(xs1,xs2) = split xs
in
merge (mergeSort xs1) (mergeSort xs2)
If you don't care too much about memory usage, you can just use Data.IntSet and a function to find all factors given a number to do this.
First, let's make a function that returns an IntSet of all factors of a number-
import qualified Data.IntSet as IntSet
factors :: Int -> IntSet.IntSet
factors n = IntSet.fromList . f $ 1 -- Convert the list of factors into a set
where
-- Actual function that returns the list of factors
f :: Int -> [Int]
f i
-- Exit when i has surpassed square root of n
| i * i > n = []
| otherwise = if n `mod` i == 0
-- n is divisible by i - add i and n / i to the list
then i : n `div` i : f (i + 1)
-- n is not divisible by i - continue to the next
else f (i + 1)
Now, once you have the IntSet corresponding to each number, you just have to do a intersection on them to get the result
commonFactors :: Int -> Int -> Int -> [Int]
commonFactors n1 n2 n3 = IntSet.toList $ IntSet.intersection (factors n3) $ IntSet.intersection (factors n1) $ factors n2
That works but is a bit ugly. How about making an intersections function that can take multiple IntSets and produce a final intersection result.
intersections :: [IntSet.IntSet] -> IntSet.IntSet
intersections [] = IntSet.empty
intersections (t:ts) = foldl IntSet.intersection t ts
That should fold on a list of IntSets to find the final intersection
Now you can refactor commonFactors to-
commonFactors :: Int -> Int -> Int -> [Int]
commonFactors n1 n2 n3 = IntSet.toList . intersections $ [factors n1, factors n2, factors n3]
Better? I'd think so. How about one last improvement, a general commonFactors function for n amount of ints
commonFactors :: [Int] -> [Int]
commonFactors = IntSet.toList . intersections . map factors
Note that this is using an IntSet, so it is naturally limited to Ints. If you want to use Integer instead - just replace IntSet with a regular Set Integer
Output
> commonFactors [234944, 246744, 144456]
[1,2,4,8]
You should use the standard algorithm where you prime factorize their GCD:
import Data.List
import qualified Data.Map.Strict as M
-- infinite list of primes
primes :: [Integer]
primes = 2:3:filter
(\n -> not $ any
(\p -> n `mod` p == 0)
(takeWhile (\p -> p * p <= n) primes))
[5,7..]
-- prime factorizing a number
primeFactorize :: Integer -> [Integer]
primeFactorize n
| n <= 1 = []
-- we search up to the square root to find a prime factor
-- if we find one then add it to the list, divide and recurse
| Just p <- find
(\p -> n `mod` p == 0)
(takeWhile (\p -> p * p <= n) primes) = p:primeFactorize (n `div` p)
-- if we don't then the number has to be prime so we're done
| otherwise = [n]
-- count the number of each element in a list
-- e.g.
-- getCounts [1, 2, 2, 3, 4] == fromList [(1, 1), (2, 2), (3, 1), (4, 1)]
getCounts :: (Ord a) => [a] -> M.Map a Int
getCounts [] = M.empty
getCounts (x:xs) = M.insertWith (const (+1)) x 1 m
where m = getCounts xs
-- get all possible combinations from a map of counts
-- e.g. getCombos (M.fromList [('a', 2), ('b', 1), ('c', 2)])
-- == ["","c","cc","b","bc","bcc","a","ac","acc","ab","abc","abcc","aa","aac","aacc","aab","aabc","aabcc"]
getCombos :: M.Map a Int -> [[a]]
getCombos m = allFactors
where
list = M.toList m
factors = fst <$> list
counts = snd <$> list
possible = (\n -> [0..n]) <$> counts
allCounts = sequence possible
allFactors = (\count -> concat $ zipWith replicate count factors) <$> allCounts
-- get the common factors of a list of numbers
commonFactorsList :: [Integer] -> [Integer]
commonFactorsList [] = []
commonFactorsList l = sort factors
where
totalGcd = foldl1 gcd l
-- then get the combinations them and take their products to get the factor
factors = map product . getCombos . getCounts . primeFactorize $ totalGcd
-- helper function for 3 numbers
commonFactors3 :: Integer -> Integer -> Integer -> [Integer]
commonFactors3 a b c = commonFactorsList [a, b, c]
I'm trying to trim a list of random numbers so that sum of the numbers in [0,1] in the resulting smaller list accumultates to a value under 1.
This is interesting in a sense that average of these list prefix lengths is e, somehow.
While getting the length of prefix I encountered a problem - I managed to get the program to work on a determined infinite list, or a slice of random list, but the program hangs on infinite random list. What am I doing wrong?
import System.Random
-- Count list items that accumulate to 1.
count :: (Num a, Ord a) => [a] -> Int
count xs = 1 + length xs'
where xs'= takeWhile (< 1) $ scanl1 (+) xs
-- Works of infinite list
a = (return (repeat 0.015)) :: IO [Double]
fa = fmap count a
--67
-- Works on trimmed list of randoms
rio = randomRIO (0::Double, 1)
b = sequence $ take 10 (repeat rio)
fb = fmap count b
-- fb is usually 2 to 5
-- Hangs on infinite list of randoms
c = sequence (repeat rio)
fc = fmap count c
-- fc hangs... ;(
You can define an IO action to create an infinite stream of ranged random numbers like so:
import System.Random
randomRIOs :: (Random a) => (a, a) -> IO [a]
randomRIOs (a, b) = randomRs (a, b) <$> newStdGen
After which, the following works fine with your definition of count:
main = do
n <- count <$> randomRIOs (0::Double, 1)
print n
You can't really have an infinite list of random numbers, because randomness is too strict. So, you can't have the call to sequence outside of your call to count. One obvious thing you could try would be a partial reimplementation of sequence inside of count itself:
count :: (Num a, Ord a, Monad m) => [m a] -> m (Maybe Int)
count = go 0 0
where go n total [] = pure Nothing
go n total (x:xs) = do
num <- x
let total' = total + num
n' = succ n
if total' >= 1
then pure $ Just n'
else go n' total' xs
I've also amended the result to return a Maybe, because it seems wrong to return 1 for an empty list (as yours did), or return the length of a list even if its elements sum to something less than 1.
Another reasonable change would be to not accept [m a], but just a single m a, which can reliably produce a value any number of times. Then we don't have to worry about the input running out, and so no Maybe is needed:
count :: (Num a, Ord a, Monad m) => m a -> m Int
count m = go 0 0
where go n total = do
num <- m
let total' = total + num
n' = succ n
if total' >= 1
then pure n'
else go n' total'
Then you can simply call count $ randomRIO (0::Double, 1), and it will produce as many random numbers as are needed.
The point of this assignment is to understand list comprehensions.
Implementing Goldbach's conjecture for some natural number (otherwise the behavior does not matter) using several pre-defined functions and under the following restrictions:
no auxiliary functions
no use of where or let
only one defining equation on the left-hand side and the right-hand side must be a list comprehension
the order of the pairs in the resulting list is irrelevant
using functions from Prelude is allowed
-- This part is the "library"
dm :: Int -> [ Int ] -> [ Int ]
dm x xs = [ y | y <- xs , y `mod ` x /= 0]
da :: [ Int ] -> [ Int ]
da ( x : xs ) = x : da ( dm x xs )
primes :: [ Int ]
primes = da [2 ..]
-- Here is my code
goldbach :: Int -> [(Int,Int)]
-- This is my attempt 1
goldbach n = [(a, b) | n = a + b, a <- primes, b <- primes, a < n, b < n]
-- This is my attempt 2
goldbach n = [(a, b) | n = a + b, a <- takeWhile (<n) primes, b <- takeWhile (<n) primes]
Expected result: a list of all pairs summing up to the specified integer. But GHC complains that in the comprehension, n is not known. My gut tells me I need some Prelude function(s) to achieve what I need, but which one?
Update
parse error on input ‘=’
Perhaps you need a 'let' in a 'do' block?
e.g. 'let n = 5' instead of 'n = 5'
Disregarding the weird error you are talking about, I think that the problem you actually have is the following:
As mentioned by #chi and me, you can't use a and b in your final comprehension before you define a and b.
so you have to move it to the and.
Also: equality of integers is checked with (==) not (=) in haskell.
So you also need to change that.
This would be the complete code for your final approach:
goldbach n = [(a, b) | a <- takeWhile (<n) primes, b <- takeWhile (<n) primes, n == a + b]
A small test yields:
*Main> goldbach 5
[(2,3),(3,2)]
Update
If you want to achieve what you wrote in your comment, you can just add another condition to your comprehension
n `mod` 2 == 0
or even better: Define your funtion with a guard like this:
goldbach n
| n `mod` 2 == 0 = [(a, b) | a <- takeWhile (<n) primes, b <- takeWhile (<n) primes, n == a + b]
| otherwise = []
However, if I am not mistaken this has nothing to do with the actual Godbach conjecture.
This is for a class
We're supposed to write 3 functions :
1 : Prints list of fibbonaci numbers
2 : Prints list of prime numbers
3 : Prints list of fibonacci numbers whose indexes are prime
EG : Let this be fibbonaci series
Then In partC - certain elements are only shown
1: 1
*2: 1 (shown as index 2 is prime )
*3: 2 (shown as index 3 is prime )
4: 3
*5: 5 (shown )
6: 8
*7: 13 (shown as index 7 prime and so on)
I'm done with part 1 & 2 but I'm struggling with part 3. I created a function listNum that creates a sort of mapping [Integer, Integer] from the Fibbonaci series - where 1st Int is the index and 2nd int is the actual fibbonaci numbers.
Now my function partC is trying to stitch snd elements of the fibonaci series by filtering the indexes but I'm doing something wrong in the filter step.
Any help would be appreciated as I'm a beginner to Haskell.
Thanks!
fib :: [Integer]
fib = 0 : 1 : zipWith (+) fib (tail fib)
listNum :: [(Integer, Integer)]
listNum = zip [1 .. ] fib
primes :: [Integer]
primes = sieve (2 : [3,5 ..])
where
sieve (p:xs) = p : sieve [x | x <- xs , x `mod` p > 0]
partC :: [Integer] -- Problem in filter part of this function
partC = map snd listNum $ filter (\x -> x `elem` primes) [1,2 ..]
main = do
print (take 10 fib) -- Works fine
print (take 10 primes) --works fine
print (take 10 listNum) --works fine
print ( take 10 partC) -- Causes error
Error :
prog0.hs:14:9: error:
• Couldn't match expected type ‘[Integer] -> [Integer]’
with actual type ‘[Integer]’
• The first argument of ($) takes one argument,
but its type ‘[Integer]’ has none
In the expression:
map snd listNum $ filter (\ x -> x `elem` primes) [1, 2 .. ]
In an equation for ‘partC’:
partC
= map snd listNum $ filter (\ x -> x `elem` primes) [1, 2 .. ]
|
14 | partC = map snd listNum $ filter (\x -> x `elem` primes) [1,2 ..]
Here's what I think you intended as the original logic of partC. You got the syntax mostly right, but the logic has a flaw.
partC = snd <$> filter ((`elem` primes) . fst) (zip [1..] fib)
-- note that (<$>) = fmap = map, just infix
-- list comprehension
partC = [fn | (idx, fn) <- zip [1..] fib, idx `elem` primes]
But this cannot work. As #DanRobertson notes, you'll try to check 4 `elem` primes and run into an infinite loop, because primes is infinite and elem tries to be really sure that 4 isn't an element before giving up. We humans know that 4 isn't an element of primes, but elem doesn't.
There are two ways out. We can write a custom version of elem that gives up once it finds an element larger than the one we're looking for:
sortedElem :: Ord a => a -> [a] -> Bool
sortedElem x (h:tl) = case x `compare` h of
LT -> False
EQ -> True
GT -> sortedElem x tl
sortedElem _ [] = False
-- or
sortedElem x = foldr (\h tl -> case x `compare` h of
LT -> False
EQ -> True
GT -> tl
) False
Since primes is a sorted list, sortedElem will always give the correct answer now:
partC = snd <$> filter ((`sortedElem` primes) . fst) (zip [1..] fib)
However, there is a performance issue, because every call to sortedElem has to start at the very beginning of primes and walk all the way down until it figures out whether or not the index is right. This leads into the second way:
partC = go primeDiffs fib
where primeDiffs = zipWith (-) primes (1:primes)
-- primeDiffs = [1, 1, 2, 2, 4, 2, 4, 2, 4, 6, ...]
-- The distance from one prime (incl. 1) to the next
go (step:steps) xs = x:go steps xs'
where xs'#(x:_) = drop step xs
go [] _ = [] -- unused here
-- in real code you might pull this out into an atOrderedIndices :: [Int] -> [a] -> [a]
We transform the list of indices (primes) into a list of offsets, each one building on the next, and we call it primeDiffs. We then define go to take such a list of offsets and extract elements from another list. It first drops the elements being skipped, and then puts the top element into the result before building the rest of the list. Under -O2, on my machine, this version is twice as fast as the other one when finding partC !! 5000.
I'm currently working on a program which computes amicable pairs (Project Euler Problem 21). I've already found the solution, however I noticed that a flaw in my program was that it evaluates all of the numbers of the set [1..] whether or not we have already found the number to be a pair.
i.e. If currently evaluating 220 and 284 is found to be it's pair, however continuing on through when the map function gets to 284 it shouldn't evaluate it again.
import Data.List
properDivisors :: (Integral a) => a -> [a]
properDivisors n = [x | x <- [1..n `div` 2],
n `mod` x == 0 ]
amicablePairOf :: (Integral a) => a -> Maybe a
amicablePairOf a
| a == b = Nothing
| a == dOf b = Just b
| otherwise = Nothing
where dOf x = sum (properDivisors x)
b = dOf a
getAmicablePair :: (Integral a) => a -> [a]
getAmicablePair a = case amicablePairOf a of
Just b -> [a,b]
Nothing -> []
amicables = foldr (++) [] ams
where ams = map getAmicablePair [1..]
As an example:
take 4 amicables
returns:
[220,284,284,220]
I'm fairly new to Haskell and functional programming so forgive me if it an obvious solution.
Your problem is, that you try to safe work by outputting both amicable numbers. But actually, you don't safe very much, because your function still calculates for both numbers, whether they are amicable. Why not do it like this:
import Data.List
divSum :: (Integral a) => a -> [a]
divSum n = sum (filter (\a -> a `mod` n == 0) [1..n `div` 2])
isAmicable :: (Integral a) => a -> Bool
isAmicable a = a /= b && a == c where
b = divSum a
c = divSum b
amicables = filter isAmicable [1..]
Perhaps a slight modification in getAmicablePair helps?
getAmicablePair :: (Integral a) => a -> [a]
getAmicablePair a = case amicablePairOf a of
Just b -> if a < b then [a,b] else []
Nothing -> []
... so you just get pairs with a smaller first element