Exercise Multicomposition , functions in list - list

This is an exercise:
-- Ex 12: recall the binary function composition operation
-- (f . g) x = f (g x). In this exercise, your task is to define a function
-- that takes any number of functions given as a list and composes them in the
-- same order than they appear in the list.
--
-- Examples:
-- multiCompose [] "foo" ==> "foo"
-- multiCompose [] 1 ==> 1
-- multiCompose [(++"bar")] "foo" ==> "foobar"
-- multiCompose [reverse, tail, (++"bar")] "foo" ==> "raboo"
-- multiCompose [(3*), (2^), (+1)] 0 ==> 6
-- multiCompose [(+1), (2^), (3*)] 0 ==> 2
As beginner, I am not able to solve that.
I tried many approach, this one does not work :
multiCompose [] = (1*) $
multiCompose fs = (multiCompose (init fs)) (last fs) $
Following my current understanding, it should work since it can be developed as follow :
multicompose [(+1), (2^), (3*)] = multiCompose [(+1), (2^)] (3*) $
= multiCompose [(+1)] (2^) $ (3*) $
= multiCompose [] (+1) $ (2^) $ (3*) $
= (1*) $ (+1) $ (2^) $ (3*) $
My questions
Could you help me with a valid answer to this exercise ?
Could you help me to understand why my solution does not work ?
Thank you so much

Your forgot the argument, and one more $:
multicompose [(+1), (2^), (3*)] $ x
-- = multiCompose [(+1), (2^)] (3*) $ x
-- here |
= multiCompose [(+1), (2^)] $ (3*) $ x
= multiCompose [(+1)] $ (2^) $ (3*) $ x
= multiCompose [] $ (+1) $ (2^) $ (3*) $ x
= (+1) $ (2^) $ (3*) $ x
Instead of [a,b,c,d] = [a,b,c] ++ [d], use the identity [a,b,c,d] = [a] ++ [b,c,d] = a : [b,c,d]:
= (+1) $ (2^) $ (3*) $ x
= (+1) $ (2^) $ (3*) $ multiCompose [ ] $ x
= (+1) $ (2^) $ multiCompose [ (3*)] $ x
= (+1) $ multiCompose [ (2^), (3*)] $ x
You can take it from here. In particular, multiCompose [] x = x must hold, and is a valid definition for the [] argument case.

Related

Why do these expressions have different levels of ambiguity?

I am writing this function:
||| Returns the ten largest values in the list.
top_ten : Ord a => List a -> List a
My first attempt was a pointfree implementation using function composition:
top_ten = take 10 . reverse . sort
But this gave the following error:
Main.idr:3:9:When checking right hand side of top_ten with expected type
List a -> List a
Can't disambiguate name: Prelude.List.take, Prelude.Stream.take
My second attempt was a straightforward pointed implementation:
top_ten xs = take 10 (reverse (sort xs))
That works, as do these:
top_ten xs = take 10 $ reverse $ sort xs
top_ten xs = take 10 (reverse $ sort xs)
top_ten xs = take 10 $ reverse . sort $ xs
top_ten xs = take 10 (reverse . sort $ xs)
However, these do not:
top_ten xs = take 10 . reverse $ sort xs
top_ten xs = take 10 . reverse . sort $ xs
top_ten xs = take 10 $ (reverse . sort) xs
top_ten xs = (take 10 . reverse) (sort xs)
top_ten xs = take 10 ((reverse . sort) xs)
What exactly is going on here? What is causing these equivalent expressions to have different levels of ambiguity?
Depending on the imports you have in scope (or functions from the Prelude) Idris is not capable to choose the correct functions as András Kovács said in his comment.
You can however help idris:
top_ten: Ord a => List a -> List a
top_ten = with Prelude.List take 10 . reverse . sort

Haskell - caesar cipher - non exhaustive pattern

Execution of the following code results in non-exhaustive pattern error. I can't figure it out why. Please help. Thanks.
module Cipher where
import Data.Char
caesar :: Int -> [Char] -> [Char]
caesar n [] = []
caesar n st = go n st
where go nn (x:xs)
| (x:xs) == [] = []
| ((+nn) $ ord x) > 122 = (chr $ (+nn) 96) : go nn xs
| ((+nn) $ ord x) >= 97 && ((+nn) $ ord x) <=122 = (chr.(+nn) $ ord x) : go nn xs
| otherwise = error "input error"
I think the error lies in the following line(s)
where go nn (x:xs)
| (x:xs) == [] = []
the match (x:xs) == [] will never be true as the first one is always a list with a (real) head and a (maybe empty) tail
you can fix this by
where go _ [] = []
go nn (x:xs) | ((+nn) $ ord x) > 122 = (chr $ (+nn) 96) : go nn xs
| ((+nn) $ ord x) >= 97 && ((+nn) $ ord x) <=122 = (chr.(+nn) $ ord x) : go nn xs
| otherwise = error "input error"
Though this style is highly unreadable - i recommend changing from (+nn) $ ord x to something like ord x + nn as well as chr (ord x + nn).
Moreover you are not accounting for
whitespace in your transformation as well as
interpunction,
negative numbers and
upper case letters!
As this seems to be a homework/exercise I won't give the idiomatic solution, but only a hint that there is a function called map that you should definitely look up and use!
Also your function go is not necessary you can write the algorithm completely without it:
caesar :: Int -> String -> String
caesar _ [] = []
caesar n (x:xs)
| 122 < ord x + n = chr (96 + n) : caesar n xs
| 97 <= ord x + n && ord x + n <=122 = chr (ord x + n) : caesar n xs
| otherwise = error "input error"
Please test with "Alea, iacta esto!" and not "foo" - you'll find more bugs with the first test case.
Update:
the idiomatic way to solve a problem, where you have a list and transform every element with a function is using map, so for example
> map (\x -> x + 3) [1..3]
[4,5,6]
thus you need a function
cipher :: Int -> Char -> Char
cipher n x
| isDigit x = chr $ ord '0' + (ord x - ord '0' + n'') `mod` 10
| isLower x = chr $ ord 'a' + (ord x - ord 'a' + n' ) `mod` 26
| isUpper x = chr $ ord 'A' + (ord x - ord 'A' + n' ) `mod` 26
| otherwise = x
where n' = n `mod` 26 -- for the letters
n'' = n `mod` 10 -- for the digits
caesar :: Int -> String -> String
caesar n xs = map (cipher n) xs
Your go function doesn't have a case that matches an empty list. The otherwise guard doesn't help here since the pattern go nn (x:xs) doesn't match to begin with.
Try this:
caesar :: Int -> [Char] -> [Char]
caesar n [] = []
caesar n st = go n st
where go nn (x:xs)
| (x:xs) == [] = []
| ((+nn) $ ord x) > 122 = (chr $ (+nn) 96) : go nn xs
| ((+nn) $ ord x) >= 97 && ((+nn) $ ord x) <=122 = (chr.(+nn) $ ord x) : go nn xs
| otherwise = error "input error"
go _ _ = error "fix me"

Without using drop, how to take and print alternate lines (odd or even) in a list?

I have written a working version using drop here:
main = do cs <- getContents
putStr $ unlines $ oddL $ lines cs
oddL :: [a] -> [a]
oddL [] = []
oddL (x:xs) = x : (oddL $ drop 1 xs)
but I was wondering if there is a way to do it without drop? Even if it is not as efficient.
oddL :: [a] -> [a]
oddL (x:_:xs) = x : oddL xs -- "forget" the even element
oddL [x] = [x]
oddL _ = [ ]
Hint: replace the x:xs pattern with a [x] pattern and an x1 : x2 : xs pattern.
You can also reuse library code for this, as in
import Data.List.Split
oddL = map head . chunksOf 2

Haskell: Pattern Matching with Lists

I'm trying to make a function that takes in a list, and if one of the elements is negative, then any elements in that list that are equal to its positive counterpart should be changed to 0. Eg, if there is a -2 in a list, then all 2's in that list should be changed to 0.
Any ideas why it only works for some cases and not others? I'm not understanding why this is, I've looked it over several times.
changeToZero [] = []
changeToZero [x] = [x]
changeToZero (x:zs:y:ws) | (x < 0) && ((-1)*(x) == y) = x : zs : 0 : changeToZero ws
changeToZero (x:xs) = x : changeToZero xs
changeToZero [-1,1,-2,2,-3,3]
-- [-1,1,-2,2,-3,3]
changeToZero [-2,1,2,3]
-- [-2,1,0,3]
changeToZero [-2,1,2,3,2]
-- [-2,1,0,3,2]
changeToZero [1,-2,2,2,1]
-- [1,-2,2,0,1]
I think a list comprehension is both clearer and easier to get right here.
changeToZero xs = [if x > 0 && (-x) `elem` xs then 0 else x | x <- xs]
If you need something more efficient, you can build a set of the negative elements and check that instead of using elem.
import qualified Data.Set as Set
changeToZero' xs = [if (-x) `Set.member` unwanted then 0 else x | x <- xs]
where unwanted = Set.fromList $ filter (< 0) xs
you don't anctually remember which negative symbols you found in the list
import qualified Data.Set as S
changeToZero :: [Int] -> [Int]
changeToZero [] = []
changeToZero xs = reverse . snd $ foldl f (S.empty,[]) xs
where
f (negs,res) x | x < 0 = (S.insert (-x) negs, x:res)
| S.member x negs = (negs,0:res)
| otherwise = (negs,x:res)
Well, building on the answer from #jdevelop, if the negative has to appear before the positive in order to count, then you can build the result with a single pass over the input, without the need to reverse it:
import qualified Data.Set as S
import Control.Monad.State
changeToZero :: [Int] -> [Int]
changeToZero xs = evalState (mapM f xs) S.empty where
f x | x < 0 = modify (S.insert (-x)) >> return x
| otherwise = gets (S.member x) >>= \hasNeg -> return $ if hasNeg then 0 else x
In this way, you can get an answer to
take 4 $ changeToZero $ 1 : (-2) : 3 : 2 : undefined
where the other solutions will fail.
** Edit **
Here is the same thing, but without the State monad, which makes it easier to understand:
changeToZero' :: [Int] -> [Int]
changeToZero' = go S.empty where
go _ [] = []
go s (x:xs) | x < 0 = x : go (S.insert (-x) s) xs
| S.member x s = 0 : go s xs
| otherwise = x : go s xs

Haskell Creating list of numbers

Hi
Im new to Haskell and wish to write a simple code.
I want to write a function which creates a list of numbers.
Where it starts of with 1 and increase with 2n+1 and 3n+1
so for example output should be like
take 6 myList = [1,3,4,7,9,10]
I think i need to use recursion but not sure how to do
it in list format.
Any help will be appreciated. Thanks
Actually, I am not sure if I get your idea.
But Is this what you want?
generator list = list ++ generator next
where
next = (map (\n -> 2 * n + 1) list) ++ (map (\n -> 3 * n + 1) list)
Oh, you can use generator [1] to fire up. like this:
take 100 $ generator [1]
merge xs [] = xs
merge [] ys = ys
merge (x:xs) (y:ys) | x == y = x : merge xs ys
| x < y = x : merge xs (y:ys)
| otherwise = y : merge (x:xs) ys
print $ take 10 $ merge [1,3..] [1,4..]
--[1,3,4,5,7,9,10,11,13,15]
As luqui said, we could use info such as do duplicates matter and does order matter. If the answers are no and no then a simple concatMap works fine:
myList = 1 : concatMap (\n -> 2*n+1 : 3*n+1 : []) myList
Results in:
> take 20 myList
[1,3,4,7,10,9,13,15,22,21,31,19,28,27,40,31,46,45,67,43]
If the answers are yes and yes then I imagine it could be cleaner, but this is sufficient:
myList = abs
where
abs = merge as bs
as = 1 : map (\n -> 2*n+1) abs
bs = 1 : map (\n -> 3*n+1) abs
merge (x:xs) (y:ys)
| x == y = x : merge xs ys
| x < y = x : merge xs (y:ys)
| otherwise = y : merge (x:xs) ys
Results in:
> take 20 myList
[1,3,4,7,9,10,13,15,19,21,22,27,28,31,39,40,43,45,46,55]