I have to write a Haskell program that does the following:
Main> dotProduct [(1,3),(2,5),(3,3)] 2
[(2,3),(4,5),(6,3)]
I have to do it both with and without map function.
I already did it without map, but I have no clue to do it with map.
My dotProduct without map function:
dotProduct :: [(Float, Integer)] -> Float -> [(Float, Integer)]
dotProduct [] _ = []
dotProduct [(x,y)] z = [(x*z,y)]
dotProduct ((x,y):xys) z = (x*z,y):dotProduct (xys) z
So I really need help with the map version.
Rather than starting by trying to fit map in somehow, consider how you might simplify and generalize your current function. Starting from this:
dotProduct :: [(Float, Integer)] -> Float -> [(Float, Integer)]
dotProduct [] _ = []
dotProduct [(x,y)] z = [(x*z,y)]
dotProduct ((x,y):xys) z = (x*z,y):dotProduct (xys) z
First, we'll rewrite the second case using the (:) constructor:
dotProduct ((x,y):[]) z = (x*z,y):[]
Expanding the [] in the result using the first case:
dotProduct ((x,y):[]) z = (x*z,y):dotProduct [] z
Comparing this to the third case, we can see that they're identical except for this being specialized for when xys is []. So, we can simply eliminate the second case entirely:
dotProduct :: [(Float, Integer)] -> Float -> [(Float, Integer)]
dotProduct [] _ = []
dotProduct ((x,y):xys) z = (x*z,y):dotProduct (xys) z
Next, generalizing the function. First, we rename it, and let dotProduct call it:
generalized :: [(Float, Integer)] -> Float -> [(Float, Integer)]
generalized [] _ = []
generalized ((x,y):xys) z = (x*z,y):generalized (xys) z
dotProduct :: [(Float, Integer)] -> Float -> [(Float, Integer)]
dotProduct xs z = generalized xs z
First, we parameterize it by the operation, specializing to multiplication for dotProduct:
generalized :: (Float -> Float -> Float) -> [(Float, Integer)] -> Float -> [(Float, Integer)]
generalized _ [] _ = []
generalized f ((x,y):xys) z = (f x z,y):generalized f (xys) z
dotProduct :: [(Float, Integer)] -> Float -> [(Float, Integer)]
dotProduct xs z = generalized (*) xs z
Next, we can observe two things: generalized doesn't depend on arithmetic directly anymore, so it can work on any type; and the only time z is used is as the second argument to f, so we can combine them into a single function argument:
generalized :: (a -> b) -> [(a, c)] -> [(b, c)]
generalized _ [] = []
generalized f ((x,y):xys) = (f x, y):generalized f (xys)
dotProduct :: [(Float, Integer)] -> Float -> [(Float, Integer)]
dotProduct xs z = generalized (* z) xs
Now, we note that f is only used on the first element of a tuple. This sounds useful, so we'll extract that as a separate function:
generalized :: (a -> b) -> [(a, c)] -> [(b, c)]
generalized _ [] = []
generalized f (xy:xys) = onFirst f xy:generalized f (xys)
onFirst :: (a -> b) -> (a, c) -> (b, c)
onFirst f (x, y) = (f x, y)
dotProduct :: [(Float, Integer)] -> Float -> [(Float, Integer)]
dotProduct xs z = generalized (* z) xs
Now we again observe that, in generalized, f is only used with onFirst, so we again combine them into a single function argument:
generalized :: ((a, c) -> (b, c)) -> [(a, c)] -> [(b, c)]
generalized _ [] = []
generalized f (xy:xys) = f xy:generalized f (xys)
dotProduct :: [(Float, Integer)] -> Float -> [(Float, Integer)]
dotProduct xs z = generalized (onFirst (* z)) xs
And once again, we observe that generalized no longer depends on the list containing tuples, so we let it work on any type:
generalized :: (a -> b) -> [a] -> [b]
generalized _ [] = []
generalized f (x:xs) = f x : generalized f xs
Now, compare the code for generalized to this:
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
It also turns out that a slightly more general version of onFirst also exists, so we'll replace both that and generalized with their standard library equivalents:
import Control.Arrow (first)
dotProduct :: [(Float, Integer)] -> Float -> [(Float, Integer)]
dotProduct xs z = map (first (* z)) xs
dotProduct xs z = map (\(x,y) -> (x*z,y)) xs
The (\(x,y) -> (x*z,y)) part is a function which takes a pair and returns a new pair that's like the old one, except its first component is multiplied by z. The map function takes a function and applies it to each element in a list. So if we pass the (\(x,y) -> (x*z,y)) function to map, it will apply that function to every element in xs.
Although are you sure your first one is correct? The dot product operation is usually defined so that it takes two vectors, multiplies corresponding component and then sums it all together. Like this:
dotProduct xs ys = sum $ zipWith (*) xs ys
EEVIAC already posted the answer, so I'll just explain how to come up with it yourself. As you probably know, map has the type signature (a -> b) -> [a] -> [b]. Now, dotProduct has the type [(Float, Integer)] -> Float -> [(Float, Integer)] and you'll call map somewhere in there, so it has to look something like this:
dotProduct theList z = map (??? z) theList
where ??? is a function of type Float -> (Float, Integer) -> (Float, Integer) - this follows immediately from the type signature of map and from the fact that we pass z to the function, which we have to do, simply because there's no other place to use it in.
The thing with map and higher order functions in general is that you have to keep in mind what the higher order function does and "simply" supply it with the correct function. As map applies a given function to all elements in the list, your function only needs to work with one element, and you can forget all about the list - map will take care of it.
Related
I'm currently trying to write a function that takes as arguments an Int and an array of Ints and for every even value in the array, it concatenates the Int to the final array.
So, something like this:
f 3 [1,2,3,4,5,6] = [1,2,3,3,4,3,5,6,3]
This is the code I imagined would work (I'm just beginning so sorry if it's bad):
f :: Int -> [Int] -> [Int]
f(x,[]) = []
f(x,y)
|even head(y) = (head(y) ++ [x] ++ f(x,drop 1 y)
|otherwise = head(y) ++ f(x,(drop 1 y))
The error I'm getting is "Couldn't match expected type of 'Int' with actual type (a3, [[a3]])'. I understand the parameters types are mismatched, but I'm not sure how a proper syntax would look like here
You use (x, []), so that means the input type would be a tuple, so f :: (Int, [Int]) -> [Int].
I would also use pattern matching instead of head and tail, so:
f :: Int -> [Int] -> [Int]
f _ [] = []
f x (y:ys)
| even y = y : x : f x ys
| otherwise = y : f x ys
You can also generalize the type signature, and work with an inner function to avoid passing the x each time:
f :: Integral a => a -> [a] -> [a]
f x = go
where go [] = []
go (y:ys)
| even y = y : x : go ys
| otherwise = y : go ys
Another way of looking at this would be using a right fold to insert the desired element after even numbers.
f :: Int -> [Int] -> [Int]
f x lst = foldr (\y i -> if even y then y:x:i else y:i) [] lst
Which we can simplify to:
f :: Int -> [Int] -> [Int]
f x = foldr (\y i -> if even y then y:x:i else y:i) []
Note that without specifying the type, the more general inferred type of f would be:
f :: (Foldable t, Integral a) => a -> t a -> [a]
For a function that maps a function to every nth element in a list:
mapEvery :: Int -> (a -> a) -> [a] -> [a]
mapEvery n f = zipWith ($) (drop 1 . cycle . take n $ f : repeat id)
Is it possible to implement this with foldr like ordinary map?
EDIT: In the title, changed 'folder' to 'foldr'. Autocorrect...
Here's one solution
mapEvery :: Int -> (a -> a) -> [a] -> [a]
mapEvery n f as = foldr go (const []) as 1 where
go a as m
| m == n = f a : as 1
| otherwise = a : as (m+1)
This uses the "foldl as foldr" trick to pass state from the left to the right along the list as you fold. Essentially, if we read the type of foldr as (a -> r -> r) -> r -> [a] -> r then we instantiate r as Int -> [a] where the passed integer is the current number of elements we've passed without calling the function.
Yes, it can:
mapEvery :: Int -> (a -> a) -> [a] -> [a]
mapEvery n f xs
= foldr (\y ys -> g y : ys) []
$ zip [1..] xs
where
g (i, y) = if i `mod` n == 0 then f y else y
And since it's possible to implement zip in terms of foldr, you could get even more fold-y if you really wanted. This even works on infinite lists:
> take 20 $ mapEvery 5 (+1) $ repeat 1
[1,1,1,1,2,1,1,1,1,2,1,1,1,1,2,1,1,1,1,2]
This is what it looks like with even more foldr and inlining g:
mapEvery :: Int -> (a -> a) -> [a] -> [a]
mapEvery _ _ [] = []
mapEvery n f xs
= foldr (\(i, y) ys -> (if i `mod` n == 0 then f y else y) : ys) []
$ foldr step (const []) [1..] xs
where
step _ _ [] = []
step x zipsfn (y:ys) = (x, y) : zipsfn ys
Now, would I recommend writing it this way? Absolutely not. This is about as obfuscated as you can get while still writing "readable" code. But it does demonstrate that this is possible to use the very powerful foldr to implement relatively complex functions.
This code is to get the distance between 2 points but i got a problem!
UPDATED by #EduardoLeon
rango2 :: Int -> [Int] -> [[Int]] -> [Int]
rango2 a b list = if (verif [(list!!a!!0),(list!!a!!1),(list!!a!!2)] (b)) then [1]
else [0]
verif :: [Int] -> [Int] -> Bool
verif a b = if ((distance a b) > a!!2) then True
else False
difference :: Num a => [a] -> [a] -> [a]
difference xs ys = zipWith (-) xs ys
dotProduct :: Num a => [a] -> [a] -> a
dotProduct xs ys = sum $ zipWith (*) xs ys
distance :: Floating a => [a] -> [a] -> a
distance xs ys = sqrt $ dotProduct zs zs
where
zs = difference xs ys
EDITED: I cant change Int to Float, because im doing operations with lists and now
throw this error!
Proyecto.hs:71:18:
No instance for (Floating Int) arising from a use of `distance'
Possible fix: add an instance declaration for (Floating Int)
In the first argument of `(>)', namely `(distance a b)'
In the expression: ((distance a b) > a !! 2)
In the expression:
if ((distance a b) > a !! 2) then True else False
To answer your concrete question: Unlike more conventional languages, Haskell does not automatically cast integers to floats. In fact, the very notion of casting does not exist in Haskell. You need to use the function fromIntegral to convert integers to other numeric types. You could try the following in ghci:
> let x = 5 :: Integer
> sqrt x
<interactive>:3:1:
No instance for (Floating Integer) arising from a use of `sqrt'
In the expression: sqrt x
In an equation for `it': it = sqrt x
> let y = fromIntegral x :: Double
> sqrt y
2.23606797749979
I would also like to make some other suggestions regarding your coding style:
Decompose your functions into smaller functions that do exactly one thing and do it well.
The function (!!) traverses a linked list to find the n-th element. This is an O(n) operation, which is more expensive than necessary if you intend to retrieve multiple elements from the same list. Prefer solutions that avoid traversing the same list more than once.
Here is how I would find the distance between two points:
difference :: Num a => [a] -> [a] -> [a]
difference xs ys = zipWith (-) xs ys
dotProduct :: Num a => [a] -> [a] -> a
dotProduct xs ys = sum $ zipWith (*) xs ys
distance :: Floating a => [a] -> [a] -> a
distance xs ys = sqrt $ dotProduct zs zs
where
zs = difference xs ys
I was searching and i saw that i need to change Int to Float?
Just change the type signature to Float and things will start working:
verif :: [Float] -> [Float] -> Bool
You need to change the type signature of your code to indicate that it works with floating data since sqrt function operates on that. A more generic solution would be this:
verif :: (Floating a, Ord a) => [a] -> [a] -> Bool
verif a b = if (sqrt((((b!!0)-(a!!0))*((b!!0)-(a!!0)))+(((b!!1)-(a!!1))*((b!!1)-(a!!1)))) < a!!3)
then True
else if (sqrt((((b!!0)-(a!!0))*((b!!0)-(a!!0)))+(((b!!1)-(a!!1))*((b!!1)-(a!!1)))) == a!!3)
then True
else False
The use of the !! function isn't encouraged in Haskell. I would suggest you to rewrite the function in a more functional way.
I suggest that you revisit your design. What are the meanings of the lists a and b in verif? It looks like you are finding the distance between two points. You can create a type:
data Point = Point Double Double
and a function
distance :: Point -> Point -> Double
to make your code much more readable.
This should also eliminate doing the same calculation twice by using a where clause or let binding.
So I have a list of tuples:
[(1,2),(2,3),(3,4)]
for example. And I perform a calculation on its elements. The result of this should be joined to this tuple, but I don't know how.
[(1,2,103),(2,3,809),(3,4,2034)]
is the format I'm thinking of.
Assuming you have a calculation function like:
calculate :: Int -> Int -> Int
you can do
calculateAll :: [(Int, Int)] -> [(Int, Int, Int)]
calculateAll = map (\(x, y) -> (x, y, calculate x y))
or more generally:
calculateAllWith :: (a -> b -> c) -> [(a, b)] -> [(a, b, c)]
calculateAllWith f = map (\(x, y) -> (x, y, f x y))
A quite straightforward solution:
import Control.Applicative ((<*>))
mapResultOn3rd :: (a -> b -> c) -> [(a,b)] -> [(a,b,c)]
mapResultOn3rd f = map (uncurry (,,) <*> uncurry f)
For example, in ghci:
>>> mapResultOn3rd (:) [(1,[2]), (3,[4,5])]
[(1,[2],[1,2]),(3,[4,5],[3,4,5])]
Use the map function:
calc :: (Int, Int) -> (Int, Int, Int)
calc = error "Implement me"
calcList :: [(Int, Int)] -> [(Int, Int, Int)]
calcList = map calc
You could also use a list comprehension in GHCi:
Prelude> let list = [(1,2),(2,3),(3,4)]
Prelude> [(x,y,x*y) | (x,y) <- list]
[(1,2,2),(2,3,6),(3,4,12)]
http://www.haskell.org/haskellwiki/List_comprehension
Or use the list as a monad:
Prelude> do (x,y) <- list; return (x,y,x*y)
[(1,2,2),(2,3,6),(3,4,12)]
But I prefer the list comprehension :-)
i am working on an encryption algorithm and i have a type problem
i don't understand what's the problem with the types here:
multien :: [(Integer , Integer)] -> Integer
multien [] = 1
multien ((x,y):z) = y* multien z
enchelper2 :: [(Integer, Integer)] -> Integer -> Integer
the problem is here in enchelper in the (z:((mod x y),y)) expression:
Couldn't match expected type (Integer , Integer) with actual Type [(Integer, Integer)]
the z in the enchelper method here i passed it as [] (empty set) the ERROR IS IN COLUMN 40 exactly
enchelper :: Integer -> [Integer] -> [(Integer, Integer)] -> [(Integer, Integer)]
enchelper x (y:ys) z = if((enchelper2 (z:((mod x y),y)) (multien z:((mod x y),y))) == x) then z:[] else (z:((mod x y),y):(enchelper x ys z:((mod x y),y)))
In this piece of code
z : (mod x y, y)
The types are
x :: Integer
y :: Integer
z :: [(Integer, Integer)]
(mod x y, y) :: (Integer, Integer)
And note that
(:) :: a -> [a] -> [a]
So perhaps you should have instead
(mod x y, y) : z
There are then similar errors later in the line.
The problem appears to be in your use of the cons operator. z is a list of tuples of two Integers, so if you really want z before ((mod x y),y), what you want to use instead is the ++ operator, followed by a list.
Try this on for size:
enchelper :: Integer -> [Integer] -> [(Integer, Integer)] -> [(Integer, Integer)]
enchelper x (y:ys) z = if((enchelper2 (z++[((mod x y),y)]) (multien (z++[((mod x y),y)]))) == x) then z else (z++[((mod x y),y)])++(enchelper x ys (z++[((mod x y),y)]))
Or, a bit more readable:
enchelper :: Integer -> [Integer] -> [(Integer, Integer)] -> [(Integer, Integer)]
enchelper x (y:ys) z =
if ((enchelper2 foo (multien foo)) == x)
then z
else foo++(enchelper x ys foo)
where foo = z++[((mod x y),y)]