Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using map to replace elements of a list with (x-y)*(x-y), where y is the initial element

I have a bit of homework to do and I am a complete newbie to Haskell. The question I am having trouble with is to write a function which when given an integer x and a list of integers apply (x-y)*(x-y) to each element in the list and output the new list, with y being each element of the input list.

I have a very rough idea I will have to use the map function but I'm unsure how to go about it.

I have been looking at examples for squaring each element in a list and kind of understand how that works, but how I would implement the (x-y)*(x-y) with y being the current element completely baffles me.

squares :: [Int] -> [Int]
squares (x:xs) = x * x : squares xs
squares [] = []

the exact question I have been set is,

Write a function rela which takes as arguments an integer x and a list of integers. It returns a similar list, but where each element y has been replaced by (x-y)*(x-y), e.g.

Main> rela 2 [3,5,7]
[1,9,25]

I have managed to get it working after reading through some books, but the code I have made misses out the first element in the list. Any explanation why?

equation1 :: Int -> Int -> Int
equation1 x y = (x-y)*(x-y)
rela :: Int -> [Int] -> [Int]
rela x [] =[]
rela x (y:ys) = [ equation1 x y | y <- ys ]
like image 266
blane clorley Avatar asked Apr 14 '12 19:04

blane clorley


3 Answers

First of all, you should probably create a separate function that does what you want.

e.g.

f x y = (x-y)*(x-y)

Now, every time you create a function in Haskell with multiple parameters, it actually "curries" the function, which means that you get a new function when you apply the first argument to it.

So, you would get a new function by doing this

g = f 5

The expression f 5 is actually a function

And you can apply a number to 'g' and x will always be '5'

So if we want to create a function that takes two parameters, 'x' and 'y', and applies (x-y)*(x-y) to a list where y is the current element, then all we need to do is the following:

f x y = (x-y)*(x-y)
squareDifference x = map (f x) [1,2,3,4]

Which you can use by calling squareDifference 5 or any other number as an argument

A more general version would allow you to pass in a list as well

squareDifference x xs = map (f x) xs

Which you would call by doing squareDifference 3 [1,2,3]

like image 77
Wes Avatar answered Oct 22 '22 09:10

Wes


do you understand lambda functions?

map (\val -> the function) xs

is what you need.

currying is even better, but not as simple.

edit:

more conceptual...

map iterates down a list applying a function.

map (+ 3) xs

uses the currying technique mentioned above. you could also:

map (\x -> x + 3) xs

to accomplish the same thing.

like image 44
bbrittain Avatar answered Oct 22 '22 08:10

bbrittain


Simple example:

rela :: Int -> [Int] -> [Int]
rela x = map (\y -> (x-y)*(x-y))

Or might you want any perversions? -) Here you are with Applicatives:

import Control.Applicative
rela :: Int -> [Int] -> [Int]
rela x = map $ (*) <$> (x-) <*> (x-)
like image 2
Danil Onishchenko Avatar answered Oct 22 '22 09:10

Danil Onishchenko