I want to write a function very similar to filter using the odd function that takes a list and returns that list with any odd numbers squared.
ex
gchi> sqrodd [1,2,3,4,5]
[1,2,9,4,25]
what I have and believe is close is
sqrodd :: (a->Bool) -> [a] -> [a]
sqrodd odd [] = []
sqrodd odd (x:xs) = if odd x
then (x*x) :sqrodd odd xs
else x : sqrodd odd xs
but I get errors with the function definition saying "couldn't match expected type a -> Bool with actual type [a]"
27.8k10 gold badges74 silver badges165 bronze badges
Your sqrodd function has two parameters: the first is an oddness-predicate a -> Bool and the second is a list of elements [a]. In your example usage, you pass [1..5] as the first argument, in place of the a -> Bool predicate.
However, what you really want is to not have two parameters, i.e. change sqrodd to a single-parameter function sqrodd :: [a] -> [a] and just use the function odd from the Prelude.
Note that you'll still need to be a bit more restrictive in your sqrodd type because it is not true that you can apply odd or (*) on elements of any type a; you may want to read up on typeclasses once you get there to get over that next hurdle.
Comments
As you wrote yourself, you want a function that takes a list as argument and returns another list, so instead of having type signature
sqrodd :: (a->Bool) -> [a] -> [a]
You should make a function with a type signature that looks like this
sqrodd :: [a] -> [a]
which is exactly what you have written on the beginning. Because of that compiler expects, that the first argument of this function will be a function of (a -> bool). You should remove odd from arguments list and change type signature as shown above. This will cause the function to use odd from prelude instead of expecting filter function as argument.
Another way of doing it, is renaming you function as, for example sqrfiltered and then you can define sqrodd as partially applied sqrfiltered
sqrodd = sqrfiltered odd
Not tested, but it should be right.
Comments
The filter function examines each element in a list and returns a new list that only contains the elements satisfying the condition.
But what you want to accomplish is to transform a list to a new list; the new list has the same number of elements of the old one. You're not filtering out anything; you're mapping elements from one list to another according to some rules.
Here are two possible ways to write your function.
oddSquared, oddSquared' :: [Int] -> [Int]
oddSquared l = [ if (x `mod` 2 /= 0) then x^2 else x | x <- l ]
oddSquared' = map (\x -> if odd x then x^2 else x)
Comments
Explore related questions
See similar questions with these tags.