I am pretty new to Haskell and I have the data data Instruction = Add | Sub | Mul | Div | Dup | Pop deriving (Eq,Ord,Show,Generic) and I am generating lists with all possible combinations of Mul and Dup with mapM (const [Mul, Dup]) [1..n]) of size n.
I wanted only the lists starting with Dup and ending with Mul so I used filter((== Mul) . last)(filter((== Dup) . head) (mapM (const [Mul, Dup]) [1..n])) but I also want only the lists with the same number of Mul and Dup in them but I can't seem to come up with a way of doing this. How do I filter this and is there a more efficient way of doing this as there may be a huge amount of combinations as lists get bigger?
A sample list would look like this: [Dup,Mul,Dup,Mul] and [Dup,Dup,Mul,Mul] for lists of size 4.
While your approach is correct, I think it's not the most efficient one. You generate 2^N lists and then filter out many of them. Forgetting the other requirements to keep the counting simple, by requiring that we have as many Muls as Dups, we end up with only choose(N, N/2) lists (the number of subsets of size N/2 of 1..N), which is a much smaller figure.
We can instead try to avoid the filtering and generate the wanted lists, only, in the first place. I suggest the following approach, which you can modify as needed to satisfy the other requirements.
We define a function sameMulDup which takes two integers m and d and generates all the lists with m Muls and d Dups.
sameMulDup :: Int -> Int -> [[Instruction]]
sameMulDup 0 d = [replicate d Dup]
sameMulDup m 0 = [replicate d Mul]
sameMulDup m d = do
-- generate the first element
x <- [Dup, Mul]
-- compute how many m and d we have left
let (m', d') = case x of
Dup -> (m , d-1)
Mul -> (m-1, d )
-- generate the other elements
xs <- sameMulDup m' d'
return (x:xs)
Intuitively, if d=0 or m=0 there is only one possible list to include in out list-of-lists result. Otherwise, we non deterministically pick the first element, decrement the correponding counter d or m, and generate the rest.
Alternatively, the last equation can be replaced by the following more basic one:
sameMulDup m d =
map (Dup:) (sameMulDup m (d-1))
++
map (Mul:) (sameMulDup (m-1) d)
Anyway, given sameMuldup, you should be able to solve your full task.
It should be possible to define a function countPred :: a -> [a] -> Int, which counts the number of items in the list which are equal to the first argument; you can then do filter (\l -> countPred Mul l == countPred Dup l) (or alternately filter ((==) <$> countPred Mul <*> countPred Dup) if you prefer point-free form). Another approach I suppose might be to do (==0) . sum . map (\case { Mul -> 1, Dup -> (-1) }), but that strikes me as being slightly more complex than necessary.
I like chi's answer, but in a comment, I mentioned that it doesn't achieve as much sharing as it could. I speculated that the sharing would be beneficial if you iterate over the list of instructions multiple times, but worse if you iterate just once. Empirically, the sharing version appears to be faster no matter how many times you iterate, but the memory tradeoff is as predicted: worse for one iteration, better for multiple. So I thought it might be interesting to show it.
Here's how it looks. We're going to make an infinite list of answers. The first index will be how long the list of instructions will be; the second is how many Muls there are (though I'll use True and False instead of Mul and Dup). So:
bits :: [[[[Bool]]]]
bits = iterate extend [[[]]] where
extend bsss = zipWith (++)
(map (map (False:)) bsss ++ [[]])
([[]] ++ map (map (True:)) bsss)
For completeness, here's how you write a function with the same signature as chi's sameMulDup, and computing the same answer (up to the swap to Bool):
sameMulDup' :: Int -> Int -> [[Bool]]
sameMulDup' m d = bits !! (m+d) !! m
Some timings on my machine, for m=d=12, when compiled -O2:
sameMulDup , one iteration 1.35s 6480Kb
sameMulDup', one iteration 1.11s 226476Kb
sameMulDup , two iterations 4.26s 2135368Kb
sameMulDup', two iterations 1.97s 620880Kb
Here is the driver code I used for acquiring these numbers:
main :: IO ()
main = do
[sharing, twice, m, d] <- getArgs
let answer = (if read sharing then sameMulDup' else sameMulDup) (read m) (read d)
if read twice
then do
print . sum . map (sum . map fromEnum) $ answer
print . sum . map (sum . map (fromEnum . not)) $ answer
else print . sum . map (sum . map fromEnum) $ answer
There are some subtle points here:
To iterate over the list twice, we must have a way of referring to the same list in both iterations. This is answer in the above code.
We must use an iteration that actually forces all the values for it to be useful. I do this by counting up how many Trues there are, but there are other ways. (Just printing the whole list doesn't work well: the calculation's runtime is then dwarfed by the production of the String to print and the work done in transferring it to the terminal.)
Although the first iteration uses the same code in both branches of the if, it is important that this code not be shared and moved out of the if. We want the compiler to know in the else branch that answer will not be used again, so that it may garbage collect. If you write print answer >> if twice then print answer else pure (), it is not as obvious statically when the prefix of answer may be garbage collected.
In the then branch, I used two different calculations in the two loops, so that the compiler did not attempt to get clever and do the calculation just once and then print the calculated result twice.
For an assignment I need to create a function which takes a list of Ints and outputs all of a number's factors in a new list. Thing is, I have absolutely no idea how to do this. I know its signature needs to be like this though :
factors :: [Int] -> [[Int]]
factors xs = ???
So when you take a list like this : [2,5,7,8]
It outputs [[],[],[],[2,4]]
I have tried things with map, filter, mod, list comprehension or higher order functions, but since this is the first language I am learning, it's very hard for me to come up with any sort of solution.
So the first thing to do if we get stuck is to skip the programming part of the problem and start by solving the actual problem. We want to take 1 number, get the factors of that number, wrap the factors inside a list, and keep going until there are no more numbers to factor.
So how do we get the factors of a number? A number x is a factor of y if we can write y as a product of x and some other integer z. Therefor, 2 is a factor of 8 because 8 can be written as 2*4.
Using this information we also know that 8 must be divisble by 2 without rest, which it is. Great! So know we know that for any two integers x and y, if x is divisible by y without rest, y is a factor.
Lets go to haskell and try some approach with the information : " x is a factor of y if y is divided by x with no rest"
factors :: Int -> [Int]
factors y = [ x | x <- [1..y], y `mod` x == 0]
So, using a listcomp we can wrap all x:es from [1..y] and put them in a list, but if and only if
y 'mod' that specific x equals 0.
If we have a function to create a list with all the factors of one number, what if we just map that function to a list of numbers, and wrap the resulting lists in a new list, and return that list
listFactors :: [Int] -> [[Int]]
listFactors xs = map factors xs
If we do not want to show the multiplication identity 1 or the number itself we can just change the interval to [2..y-1]
I was trying to do this question:
Given three integers: GA, GB, and GC(which represent apples, oranges,
and bananas respectively) & N lines each consisting of three integers:
A, B, and C, which represent the amount of apples, oranges, and
bananas in that food, respectively.
Check if it's possible to use only certain cartons such that the total
apples, oranges, and bananas sum up to GA, Gb and GC respectively. For
each available carton, we can only choose to buy it or not to buy it.
He can't buy a certain carton more than once, and he can't buy a
fractional amount of a carton.
Sample Test Case
IN
100 100 100
3
10 10 40
10 30 10
10 60 50
OUT
no
IN
100 100 100
5
40 70 30
30 10 40
20 20 50
10 50 90
40 10 20
OUT
yes
For this problem, I have written some code but have been getting segmentation faults only and a number of errors. Plus, my algorithm is quite bad. What I do is find all subsets of the apples array such that their sum is GA, then I check to see if any of those sets have oranges and bananas to add to GB and GC. But this idea is quite slow and very difficult to code...
I believe this is somewhat a variation of the knapsack problem and can be solved in a better complexity (atleast better than O(2^N)[My current complexity] ;P ). SO, what would be a better algorithm to solve this question, and also, see my current code at PasteBin(I havent put the code on stackoverflow because it is flawed, and moreover, I believe I'll have to start from scratch with it...)
The segmentation faults are entirely your problem.
Knapsack is NP-complete, and so is this (assume input where A, B, C are always the same, and Ga = half the sum of the A's). I don't think anyone is asking you to solve NP-complete problems here.
Obviously you don't check all sets, but only those with sum A <= 100, sum B <= 100, sum C <=100.
Same situation as with this question.
This question is 2nd problem from Facebook Hackercup qualification round which is currently in progress (it will end 12th of January 12AM UTC).
It's not really fair to ask here solutions for the problems of active programming competitions.
This is a variant of the 0-1 knapsack problem. This problem is NP-hard, so there is not much hope to find a solution in polynomial time, but there exists a solution in pseudo-polynomial time which makes this problem rather easy (in the world of complex problems).
The algorithm works as follows:
Start with a collection (for instance a set) containing the tuple <0,0,0>.
For each carton <a',b',c'>: iterate over the all tuples <a,b,c> in the collection and add <a+a',b+b',c+c'> to the collection, ensure that duplicates are not added. Don't add tuples where one or more elements have exceeded the corresponding target value.
If the given collection contains the target values after the algorithm, print "yes", otherwise "no".
Optionally but strongly advisable lower-bound elimination: you can also perform lookaheads and for instance eliminate all values that will never reach the given target anymore (say you can at most add 20 apples, then all values less than 80 apples can be eleminated).
Concept 1 (Lowerbound): Since you add values of tuples together, you now that if there are tuples <a0,a1,a2> and <b0,b1,b2> left, adding these will at most increase a tuple with <a0+b0,a1+b1,a2+b2>. Now say the target is <t0,t1,t2> then you can safely eliminate a tuple <q0,q1,q2> if q0+a0+b0 < t0 (generalize to other tuple elements), since even if you can add the last tuples, it will never reach the required values. The lower bound is thus <t0-a0-b0,t1-a1-b1,t2-a2-b2>. You can generalize this for n tuples.
So first you add up all provided tuples together (for the second instance, that's <140,160,230>) and than subtract that from the target (the result is thus: <-40,-60,-130>). Each iteration, the lower bound is increased with that carton, so after the first iteration, the result for the second example is (<-40+40,-60+70,-130+30> or <0,10,-100>).
The time complexity is however O(ta^3 tb^3 tc^3) with ta, tb and tc the target values.
Example 1 (high level on the two given testcases):
INPUT
100 100 100
3
10 10 40
10 30 10
10 60 50
The set starts with {<0,0,0>}, after each iteration we get:
{<0,0,0>};
{<0,0,0>,<10,10,40>};
{<0,0,0>,<10,10,40>,<10,30,10>,<20,40,50>}; and
{<0,0,0>,<10,10,40>,<10,30,10>,<20,40,50>,<10,60,50>,<10,60,50>,<20,70,90>,<30,100,100>}, thus fail.
With underbound-elimination:
{<0,0,0>}, lowerbound <100-30,100-100,100-100>=<70,0,0> thus eliminate <0,0,0>.
{} thus print "no".
Example 2
INPUT
100 100 100
5
40 70 30
30 10 40
20 20 50
10 50 90
40 10 20
With lower-bound elimination:
{<0,0,0>} lower bound: <-40,-60,-130> thus ok.
{<0,0,0>,<40,70,30>} lower bound: <0,10,-100> (eliminate <0,0,0> because second conflicts).
{<40,70,30>,<70,80,70>} lower bound: <30,20,-60> (no elimination).
{<40,70,30>,<70,80,70>,<60,90,80>,<90,100,120>} lower bound: <50,40,-10> (eliminate <40,70,30>) upper eliminate <90,100,120>.
{<70,80,70>,<60,90,80>,<80,130,160>,<70,140,170>} lower bound: <60,90,80> (eliminate <70,80,70>) upper eliminate <80,130,160> and <70,140,170>.
{<60,90,80>,<100,100,100>} lower bound: <100,100,100> (eliminate <60,90,80>).
{<100,100,100>} thus "yes".
Haskell program
I've implemented a (not that efficient, but proof of concept) Haskell program that does the trick for an arbitrary tuple-length:
import qualified Data.Set as Set
tupleSize :: Int
tupleSize = 3
group :: Int -> [a] -> [[a]]
group _ [] = []
group n l = take n l : group n (drop n l)
empty :: Int -> Set.Set [Int]
empty n = Set.fromList [replicate n 0]
solve :: [Int] -> [[Int]] -> Bool
solve t qs = Set.member t $ mix t (lowerBound t qs) qs $ empty $ length t
lowerBound :: [Int] -> [[Int]] -> [Int]
lowerBound = foldl (zipWith (-))
lowerCheck :: [Int] -> [Int] -> Bool
lowerCheck l x = and $ zipWith (<=) l x
targetCheck :: [Int] -> [Int] -> Bool
targetCheck t x = and $ zipWith (>=) t x
takeout :: Int -> [a] -> [a]
takeout _ [] = []
takeout i (h:hs) | i == 0 = hs
| otherwise = h : takeout (i-1) hs
mix :: [Int] -> [Int] -> [[Int]] -> Set.Set [Int] -> Set.Set [Int]
mix _ _ [] s = s
mix t l (q:qs) s = mix t (zipWith(+) l q) qs $ Set.filter (lowerCheck l) $ Set.union s $ Set.filter (targetCheck t) $ Set.map (zipWith (+) q) s
reply :: Bool -> String
reply True = "yes"
reply False = "no"
main = interact $ \x -> let tuples = group tupleSize $ takeout tupleSize $ map read (words x) in reply $ solve (head tuples) (tail tuples)
You can compile an run it using:
ghc file.hs
./file < input
Conclusion: Although the worst-case behavior can be hard, the second example shows that the problem can be solve efficiently for some cases.
I'll use a simple example for what I'm trying to do.
Say I have the list:
nums = []
Now I have the function:
allNums n = nums.append(n)
So if I run the function:
allNums 6
The list nums should have the values
[6]
I know nums.append doesn't work, but what code could replace that.
Simple Answer:
You can't do that. Haskell is a pure, functional language, that means:
A function does not have any side effect.
A function does always return the same result when called with the same parameters.
A function may or may not be called, but you don't have to care about that. If it wasn't called, it wasn't needed, but because the function does not have any side effects, you won't find out.
Complex answer:
You could use the State Monad to implement something that behaves a bit like this, but this is probably out of reach for you yet.
I'm suggesting to use an infinite list instead of appending to global variable.
It's true haskell is pure functional. But also it's lazy. Every part of data is not calculated until is really needed. It also applies to collections. So you could even define a collection with elements based on previous elements of same collection.
Consider following code:
isPrime n = all (\p -> (n `mod` p) /= 0 ) $ takeWhile (\p ->p * p <= n) primes
primes = 2 : ( filter isPrime $ iterate (+1) 3 )
main = putStrLn $ show $ take 100 primes
definition of isPrime is trivia when primes list is defined. It takes pack of primes which is less or equivalent to square root of examining number
takeWhile (\p ->p * p <= n) primes
then it checks if number have only non-zero remainders in division by all of these numbers
all (\p -> (n `mod` p) /= 0 )
the $ here is an application operator
Next using this definition we taking all numbers starting from 3:
iterate (+1) 3
And filtering primes from them.
filter isPrime
Then we just prepending the first prime to it:
primes = 2 : ( ... )
So primes becomes an infinite self-referred list.
You may ask: why we prepending 2 and just no starting filtering numbers from it like:
primes = filter isPrime $ iterate (+1) 2
You could check this leads to uncomputable expression because the isPrime function needs at least one known member of primes to apply the takeWhile to it.
As you can see primes is well defined and immutable while it could have as many elements as you'll need in your logic.
According to the book this is how its done, but I am not able to get this to work. It gives me an error Not in scope: 'ld'. I'm guessing I should be importing some package but not sure which one. Also the book uses GS module at the prompt but I'm using WinGHCi that has Prelude. What am I missing here?
factors :: Int -> [Int]
factors n | n < 1 = error "not positive"
| n == 1 = []
| otherwise = p : factors (div n p)
where p = ld n
I guess this can also be done using map and filter functions? How?
I suppose the aim of the assignment is to teach you about list comprehensions, filter and similar constructs, and not to have you write functions that test for primality or create the list of divisors in any sensible way. Therefore what you need is a predicate divides,
divides :: Int -> Int -> Bool
a `divides` b = ???
Then you use that predicate for the argument to filter or in a list comprehension to find the list of divisors, and use the divisors function for your isPrime test.
You want to inspect all numbers from 1 to n, and keep them only if they divide n. The filter function can help you:
divisors n = filter ??? [1..n]
So what condition you need to put in place of ??? ?
For the isPrime function you could reuse the divisors function, you already mentioned how.
Break it down into simpler steps.
Write a function, divides :: Int -> Int -> Bool such that
x `divides` n
is true when x is a divisor of n. So, first, think about what it means for x to be a divisor of n.
Now that you have a way to check if a single number x is a divisor of n, you need to check a certain range of numbers less than n to see which ones are divisors.
Hint: In Haskell, you can generate a list of numbers from 1 to n like so: [1..n]
This is where that filter function you mention would be useful. Check its type:
filter :: (a -> Bool) -> [a] -> [a]
Just replace the a above with Int.
As far as the isPrime function, just think about what it means for a number to be prime... if you've calculated your divisors correctly, you can check the list to make sure that it matches with that property.
If this is a homework related question, you should definitely tag it with homework, then people don't feel as timid about helping out :)