Madalina
Madalina

Reputation: 85

Product of 2 list haskell

I have 2 lists, x and y, I must calculate the product of (xi^2 - yi^2 + 2*xi*yi) with xi from x
and yi from y

 List x = [2,4,5,6,8] xi = 2/3/...
 List y = [7,3,4,59,0] yi = 7/3/4...

It's a bit tricky because I can use only functions without the product function without recursion and list comprehension.

prod :: [Int] -> [Int] -> Int

I would write the product function myself:

product :: [Integer] -> Integer
product []     = 1
product i f = foldl (*) 1 [i..f]

But I don't know how to apply it to the both strings.

Upvotes: 1

Views: 1137

Answers (3)

Román García
Román García

Reputation: 425

Allow me to reuse the excelent answer of @WillemVanOnsem in a more step-by-step aproach:

First, you must join the two list somehow. zip :: [a] -> [b] -> [(a,b)] is a handy function for doing this, from two list it returns a list of pairs.

zip [2,4,5,6,8] [7,3,4,59,0] 
> [(2,7),(4,3),(5,4),(6,59),(8,0)]

Now, you must do your work with the pairs. Lets define de function you must apply to a pair:

squareB :: (Integer,Integer) -> Integer
squareB (x,y)  = x^2 - y^2 + 2*x*y

Lets use map for aplying the square of a binomial function to each pair:

multiplicands:: [Integer] -> [Integer] -> [Integer] 
multiplicands xs1 xs2 = map squareB (zip xs1 xs2)

For example:

multiplicands  [2,4,5,6,8] [7,3,4,59,0]
>[-17,31,49,-2737,64]

Now, lets fold them from the left using (*) with base case 1, ie: (((1 * x1) * x2) .... xn):

solution :: [Integer] -> [Integer] -> Integer
solution xs1 xs2 = foldl (*) 1  (multiplicands xs1 xs2)

Lets check this function:

solution [2,4,5,6,8] [7,3,4,59,0]
> 452336326

with Willems' function:

twoListProduct [2,4,5,6,8] [7,3,4,59,0]
> 4523363264

Upvotes: 1

Redu
Redu

Reputation: 26161

You may also do as follows;

quadratics :: Num a => Int -> [a] -> [a] -> a
quadratics i ns ms = ((\(f,s) -> f*f + 2*f*s - s*s) . head . drop i . zip ns) ms

*Main> quadratics 0 [2,4,5,6,8] [7,3,4,59,0]
-17
*Main> quadratics 3 [2,4,5,6,8] [7,3,4,59,0]
-2737

Upvotes: 0

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476547

Well you can define a product yourself with foldl :: (b -> a -> b) -> b -> [a] -> [b] like:

ownProduct :: Num b => [b] -> b
ownProduct = foldl (*) 1

Because a foldl starts with the initial value (1) and applies that value to the first element of the list. The result of that operation is applied to the function again but now with the second element of that list and so on until we reach the end. So foldl (*) 1 [x1,x2,...,xn] is equal to (((1*x1)*x2)*...)*xn.

Furthermore you can use a zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] function to convert two streams (one of as and one of bs) into a stream of c by applying the function element-wise.

So you can implement it like:

twoListProduct :: Num b => [b] -> [b] -> b
twoListProduct x y = foldl (*) 1 $ zipWith helper x y
    where helper xi yi = xi*xi - yi*yi + 2*xi*yi

Upvotes: 2

Related Questions