I am relatively new to Haskell, but I try to learn by reading and trying to solve problems with Project Euler. I'm currently trying to implement a function that accepts an infinite list of integers and returns an ordered list of pairwise sums of elements in the specified list. I am really looking for solutions to the specific problem that I am facing, and not advice on various strategies or approaches, but this is also welcome, since the encoder does not mean knowing how to implement the strategy, but also choosing the best Strategy is available.
My approach is based on traversing an infinite list of infinite generators and extracting elements in order with several mathematical properties that are useful in implementing my solution.
If I tried to get a sequence of pairwise sums of natural numbers, for example, this would be my code:
myList :: [Integer]
myList = [1..]
myGens :: [[Integer]]
myGens = gens myList
where
gens = \xs -> map (\x -> [x+y|y<-(dropWhile (<x) xs)]) xs
Regardless of the set of numbers used, provided that it is sorted, the following conditions are true:
- & FORALL; i & ge; 0
head (gens xs !! i) == 2*(myList !! i) - & FORALL; i, j, k? 0, l> 0,
(((gens xs) !! i) !! j) < (((gens xs) !! i+k) !! j+l)
Special cases for the second condition:
- & FORALL; i, j? 0
(((gens xs) !! i) !! j) < (((gens xs) !! i+1) !! j) - & FORALL; i, j? 0, k> 0,
(((gens xs) !! i) !! j) < (((gens xs) !! i+k) !! j)
Here is the specific code I'm trying to change:
stride :: [Integer] -> [Int] -> [[Integer]] -> [Integer]
stride xs cs xss = x : stride xs counts streams
where
(x,i) = step xs cs xss
counts = inc i cs
streams = chop i xss
step :: [Integer] -> [Int] -> [[Integer]] -> (Integer,Int)
step xs cs xss = pace xs (defer cs xss)
pace :: [Integer] -> [(Integer,Int)] -> (Integer,Int)
pace hs xs@((x,i):xt) = minim (x,i) hs xt
where
minim :: (Integer,Int) -> [Integer] -> [(Integer,Int)] -> (Integer,Int)
minim m _ [] = m
minim m@(g,i) hs (y@(h,n):ynt) | g > h && 2*(hs !! n) > h = y
| g > h = minim y hs ynt
| 2*(hs !! n) > g = m
| otherwise = minim m hs ynt
defer :: [Int] -> [[a]] -> [(a,Int)]
defer cs xss = (infer (zip cs (zip (map head xss) [0..])))
infer :: [(Int,(a,Int))] -> [(a,Int)]
infer [] = []
infer ((c,xi):xis) | c == 0 = xi:[]
| otherwise = xi:(infer (dropWhile (\(p,(q,r)) -> p>=c) xis))
The set I have given has the property that several different pairs produce the same amount. I want an efficient method of processing all repeating elements at the same time, in order to avoid increasing the cost of calculating all pairwise sums to N, since this requires M more tests if M is the number of duplicates.
Does anyone have any suggestions?
EDIT:
, , , , .
stride :: [Integer] -> [Int] -> [[Integer]] -> [Integer]
stride xs cs xss = x : stride xs counts streams
where
(x,is) = step xs cs xss
counts = foldr (\i -> inc i) cs is
streams = foldr (\i -> chop i) xss is
step :: [Integer] -> [Int] -> [[Integer]] -> (Integer,[Int])
step xs cs xss = pace xs (defer cs xss)
pace :: [Integer] -> [(Integer,Int)] -> (Integer,[Int])
pace hs xs@((x,i):xt) = minim (x,(i:[])) hs xt
where
minim :: (Integer,[Int]) -> [Integer] -> [(Integer,Int)] -> (Integer,[Int])
minim m _ [] = m
minim m@(g,is@(i:_)) hs (y@(h,n):ynt) | g > h && 2*(hs !! n) > h = (h,[n])
| g > h = minim (h,[n]) hs ynt
| g == h && 2*(hs !! n) > h = (g,n:is)
| g == h = minim (g,n:is) hs ynt
| g < h && 2*(hs !! n) > g = m
| g < h = minim m hs ynt
, inc chop:
alter :: (a->a) -> Int -> [a] -> [a]
alter = \f -> \n -> \xs -> (take (n) xs) ++ [f (xs !! n)] ++ (drop (n+1) xs)
inc :: Int -> [Int] -> [Int]
inc = alter (1+)
chop :: Int -> [[a]] -> [[a]]
chop = alter (tail)