Solve the algorithmic problem with an end recursive form - haskell

Input: List xs with arbitrary numeric elements, xs has at least two elements / Output: smallest distance between adjacent elements in the list.
-- Input: List xs with at least two numeric elements & its implementation an end recursive function.
-- Erg: Returns the smallest distance of adjacent elements from the output list.
minimumdistance :: [Int] -> Int
minimumdistance [] = error "Empty list".
minimumdistance [_] = error "Requirement is not met".
minimumdistance [a,b] = abs (a - b)
minimaldistance (x:y:xs) = helper (abs (x - y)) xs where
helper :: Int -> [Int] -> Int
helper acc [] = acc
helper acc (z:zs) = if (abs (y - z)) < acc then helper (abs (y - z)) zs else helper
acc zs
Is the function endrecursive because that we are supposed to solve the task endrecursive and I am sure because I do not have the definition yet correctly, but I also on other pages, the endrecursive representation not understood

Your code has several issues mentioned in comments.
I suggest you break this down into smaller problems. We can write a tail-recursive function to get pairs of adjacent numbers from the list.
pairs [] = error "Not long enough"
pairs [_] = error "Not long enough"
pairs lst = aux lst []
where
aux (a:b:c) acc = aux (b:c) ((a, b):acc)
aux _ acc = acc
Now, if we test this:
ghci> pairs [1, 3, 6, 7, 10]
[(7,10),(6,7),(3,6),(1,3)]
We can use map to get the differences.
ghci> map (\(a, b) -> abs (a - b)) $ pairs [1, 3, 6, 7, 10]
[3,1,3,2]
Now we just need to reduce that down to the minimum.
ghci> foldl1 min $ map (\(a, b) -> abs (a - b)) $ pairs [1, 3, 6, 7, 10]
1

In your code for the helper function, the y variable does not get updated at all. Hence it remains equal to the second element of the initial input list in all successive scopes. This is probably not what you want.
It is more reliable to just include the previous list element into your state/accumulator, together with the smallest distance seen so far. This gives the following code:
minimumDistance :: [Int] -> Int
minimumDistance [] = error "Empty list."
minimumDistance [_] = error "Requirement is not met."
minimumDistance (x:y:xs) = helper (abs (x-y), y) xs where
helper (mnd,u) [] = mnd
helper (mnd,u) (z:zs) = let d1 = abs (u-z)
in if (d1 < mnd) then helper (d1, z) zs
else helper (mnd, z) zs
Sanity check:
We can generate a small random list, and compare the result of our minimumDistance function with the one obtained by just combining a few suitable library functions. Like this:
$ ghci
GHCi, version 8.10.7: https://www.haskell.org/ghc/ :? for help
...
λ>
λ> :load q75011741.hs
[1 of 1] Compiling Main ( q75011741.hs, interpreted )
Ok, one module loaded.
λ>
λ> :type minimumDistance
minimumDistance :: [Int] -> Int
λ>
λ> import System.Random (randomRs, mkStdGen)
λ>
λ> g0 = mkStdGen 42
λ>
λ> xs = take 20 $ randomRs (0,500) g0
λ>
λ> xs
[48,151,95,271,208,466,401,23,139,95,500,306,187,389,398,297,248,94,348,91]
λ>
λ> minimumDistance xs
9
λ>
λ>
λ> zip xs (tail xs)
[(48,151),(151,95),(95,271),(271,208),(208,466),(466,401),(401,23),(23,139),(139,95),(95,500),(500,306),(306,187),(187,389),(389,398),(398,297),(297,248),(248,94),(94,348),(348,91)]
λ>
λ> map (\(a,b) -> abs(a-b)) $ zip xs (tail xs)
[103,56,176,63,258,65,378,116,44,405,194,119,202,9,101,49,154,254,257]
λ>
λ> minimum $ map (\(a,b) -> abs(a-b)) $ zip xs (tail xs)
9
λ>
So it looks OK.
Side note:
If for comparison purposes one also wants a solution based on a library-provided recursion scheme, the foldl' library function can be used. This gives the following code change:
minimumDistance (x:y:xs) = fst $ foldl' sfn acc0 xs where
acc0 = (abs(x-y), y)
sfn (mnd, pv) z = let d1 = abs (pv-z) in if (d1 < mnd) then (d1, z)
else (mnd, z)

Related

Get all rotations for a string in haskell

So I'm trying to make a function "rot" which takes a string and returns a list of strings with all possible rotations, e.g rot "abc" returns ["abc", "bca", cab"], seems very simple to do in other languages but I'm a newbie at haskell so I can't think of a way to do it. This is what I have so far:
rot :: [Char] -> [[Char]]
rot word =
let
lst = [tail word ++ [head word]]
in
lst
main = do
print(rot "abc")
It returns me "bca" as expected, but I would like a way to find all rotations and store it in a list.
Here's an example in python
def rot(word):
lst = []
for i in range(len(word)):
newWord1 = word[0:i]
newWord2 = word[i:]
newWordResult = newWord2 + newWord1
lst.append(newWordResult)
return lst
Well, you can more or less directly translate your Python code. Recursion is customarily used in functional programming instead of iteration, and it's more convenient to count from length word down to zero. Other than that, it's pretty much the same:
rot word =
let loop 0 lst = lst
loop i lst =
let newWord1 = take (i-1) word
newWord2 = drop (i-1) word
newWordResult = newWord2 ++ newWord1
in loop (i-1) (newWordResult : lst)
in loop (length word) []
One can make use of the tails and inits of a list:
Prelude Data.List> tails "abc"
["abc","bc","c",""]
Prelude Data.List> inits "abc"
["","a","ab","abc"]
we thus can use this with:
import Data.List(inits, tails)
rotated :: [a] -> [[a]]
rotated xs = [x ++ y | (x#(_:_), y) <- zip (tails xs) (inits xs)]
This produces:
Prelude Data.List> rotated "abc"
["abc","bca","cab"]
Prelude Data.List> rotated [1,4,2,5]
[[1,4,2,5],[4,2,5,1],[2,5,1,4],[5,1,4,2]]
Prelude Data.List> rotated [1.0,3.0,0.0,2.0]
[[1.0,3.0,0.0,2.0],[3.0,0.0,2.0,1.0],[0.0,2.0,1.0,3.0],[2.0,1.0,3.0,0.0]]
or as #Iceland_jack says, we can use the ParallelListComp extension to allow iterating over two lists in parallel in list comprehension without the explicit use of zip:
{-# LANGUAGE ParallelListComp #-}
import Data.List(inits, tails)
rotated :: [a] -> [[a]]
rotated xs = [x ++ y | x#(_:_) <- tails xs | y <- inits xs]
This is, simply,
rotations xs = map (take n) . take n
. tails $ xs ++ xs
where
n = length xs
It is customary to avoid length if at all possible, though here it leads to a bit more convoluted code(*) (but more often than not it leads to a simpler, cleaner code that is more true to the true nature of the problem),
rotations2 xs = map (zipWith (\a b -> b) xs)
. zipWith (\a b -> b) xs
. tails $ xs ++ xs
Testing, we get
> rotations "abcd"
["abcd","bcda","cdab","dabc"]
> rotations2 "abcd"
["abcd","bcda","cdab","dabc"]
> take 4 . map (take 4) $ rotations2 [1..]
[[1,2,3,4],[2,3,4,5],[3,4,5,6],[4,5,6,7]]
(*) edit Actually, it probably merits its own name,
takeLength :: [a] -> [b] -> [b]
takeLength = zipWith (\a b -> b)
rotations2 xs = map (takeLength xs)
. takeLength xs
. tails $ xs ++ xs

How could I make a list in Haskell by prime index?

How could I make a list where I get every number/letter which has a prime index number?
primeIndex :: [a] -> [a]
primeIndex [1..20] == [2, 3, 5, 7, 11, 13, 17, 19]
primeIndex "primesarefun" == "rieau"
A possible strategy:
Following the general approach mentioned above by #Joseph Sible-Reinstate Monica, the problem can be solved like this:
get a list of all prime numbers, say primes
use that first list to create an auxiliary list of booleans which has True elements solely at prime indices
use the second list together with classic list functions (map, filter, zip) to solve the problem
Regarding the first part, there are a number of available algorithms in the relevant page of the Haskell Wiki. We can just pick one of them.
import Data.List.Ordered
_Y :: (t -> t) -> t
_Y g = g (_Y g)
joinL :: (Ord a, Eq a) => [[a]] -> [a]
joinL ((x:xs):t) = x : union xs (joinL t)
joinL ([]:t) = joinL t
joinL [] = []
primesLME :: [Integer]
primesLME = 2 : _Y ((3:) . minus [5,7..] . joinL . map (\p-> [p*p, p*p+2*p..]))
primes = primesLME
with LME standing for Linear MErging.
Regarding the second part, a function to transform primes into the required list of booleans, say primeMask, can be taken from SO_q59092535.
-- boolean list from index list (with unfoldr):
booleansFromIndices :: [Integer] -> [Bool]
booleansFromIndices indices =
let sfn (pos,ind) = Just $ -- stepping function for unfoldr
if (null ind)
then ( False, (pos+1, []) )
else ( pos==head ind,
(pos+1, if (pos==head ind) then tail ind else ind))
in unfoldr sfn (0,indices)
primeMask :: [Bool]
primeMask = drop 1 $ booleansFromIndices primes -- 1-based indexing
Putting it all together (third and last part):
In a ghci session:
λ>
λ> take 10 primes
[2,3,5,7,11,13,17,19,23,29]
λ>
λ>
λ> take 15 primeMask
[False,True,True,False,True,False,True,False,False,False,True,False,True,False,False]
λ>
λ> take 20 $ map (\b -> if b then '1' else '0') primeMask
"01101010001010001010"
λ>
λ> str = "primesarefun"
λ>
λ> zip primeMask str
[(False,'p'),(True,'r'),(True,'i'),(False,'m'),(True,'e'),(False,'s'),(True,'a'),(False,'r'),(False,'e'),(False,'f'),(True,'u'),(False,'n')]
λ>
λ> filter fst $ zip primeMask str
[(True,'r'),(True,'i'),(True,'e'),(True,'a'),(True,'u')]
λ>
λ> map snd $ filter fst $ zip primeMask str
"rieau"
λ>
λ> primeIndex = \xs -> map snd $ filter fst $ zip primeMask xs
λ>
λ> primeIndex [1..20]
[2,3,5,7,11,13,17,19]
λ>

Split a list into non-empty sub-lists in Haskell

I have to split the given list into non-empty sub-lists each of which
is either in strictly ascending order, in strictly descending order, or contains all equal elements. For example, [5,6,7,2,1,1,1] should become [[5,6,7],[2,1],[1,1]].
Here is what I have done so far:
splitSort :: Ord a => [a] -> [[a]]
splitSort ns = foldr k [] ns
where
k a [] = [[a]]
k a ns'#(y:ys) | a <= head y = (a:y):ys
| otherwise = [a]:ns'
I think I am quite close but when I use it it outputs [[5,6,7],[2],[1,1,1]] instead of [[5,6,7],[2,1],[1,1]].
Here is a kinda ugly solution, with three reverse in one line of code :).
addElement :: Ord a => a -> [[a]] -> [[a]]
addElement a [] = [[a]]
addElement a (x:xss) = case x of
(x1:x2:xs)
| any (check a x1 x2) [(==),(<),(>)] -> (a:x1:x2:xs):xss
| otherwise -> [a]:(x:xss)
_ -> (a:x):xss
where
check x1 x2 x3 op = (x1 `op` x2) && (x2 `op` x3)
splitSort xs = reverse $ map reverse $ foldr addElement [] (reverse xs)
You can possibly get rid of all the reversing if you modify addElement a bit.
EDIT:
Here is a less reversing version (even works for infinite lists):
splitSort2 [] = []
splitSort2 [x] = [[x]]
splitSort2 (x:y:xys) = (x:y:map snd here):splitSort2 (map snd later)
where
(here,later) = span ((==c) . uncurry compare) (zip (y:xys) xys)
c = compare x y
EDIT 2:
Finally, here is a solution based on a single decorating/undecorating, that avoids comparing any two values more than once and is probably a lot more efficient.
splitSort xs = go (decorate xs) where
decorate :: Ord a => [a] -> [(Ordering,a)]
decorate xs = zipWith (\x y -> (compare x y,y)) (undefined:xs) xs
go :: [(Ordering,a)] -> [[a]]
go ((_,x):(c,y):xys) = let (here, later) = span ((==c) . fst) xys in
(x : y : map snd here) : go later
go xs = map (return . snd) xs -- Deal with both base cases
Every ordered prefix is already in some order, and you don't care in which, as long as it is the longest:
import Data.List (group, unfoldr)
foo :: Ord t => [t] -> [[t]]
foo = unfoldr f
where
f [] = Nothing
f [x] = Just ([x], [])
f xs = Just $ splitAt (length g + 1) xs
where
(g : _) = group $ zipWith compare xs (tail xs)
length can be fused in to make the splitAt count in unary essentially, and thus not be as strict (unnecessarily, as Jonas Duregård rightly commented):
....
f xs = Just $ foldr c z g xs
where
(g : _) = group $ zipWith compare xs (tail xs)
c _ r (x:xs) = let { (a,b) = r xs } in (x:a, b)
z (x:xs) = ([x], xs)
The initial try turned out to be lengthy probably inefficient but i will keep it striked for the sake of integrity with the comments. You best just skip to the end for the answer.
Nice question... but turns out to be a little hard candy. My approach is in segments, those of each i will explain;
import Data.List (groupBy)
splitSort :: Ord a => [a] -> [[a]]
splitSort (x:xs) = (:) <$> (x :) . head <*> tail $ interim
where
pattern = zipWith compare <$> init <*> tail
tuples = zipWith (,) <$> tail <*> pattern
groups = groupBy (\p c -> snd p == snd c) . tuples $ (x:xs)
interim = groups >>= return . map fst
*Main> splitSort [5,6,7,2,1,1,1]
[[5,6,7],[2,1],[1,1]]
The pattern function (zipWith compare <$> init <*> tail) is of type Ord a => [a] -> [Ordering] when fed with [5,6,7,2,1,1,1] compares the init of it by the tail of it by zipWith. So the result would be [LT,LT,GT,GT,EQ,EQ]. This is the pattern we need.
The tuples function will take the tail of our list and will tuple up it's elements with the corresponding elements from the result of pattern. So we will end up with something like [(6,LT),(7,LT),(2,GT),(1,GT),(1,EQ),(1,EQ)].
The groups function utilizes Data.List.groupBy over the second items of the tuples and generates the required sublists such as [[(6,LT),(7,LT)],[(2,GT),(1,GT)],[(1,EQ),(1,EQ)]]
Interim is where we monadically get rid of the Ordering type values and tuples. The result of interim is [[6,7],[2,1],[1,1]].
Finally at the main function body (:) <$> (x :) . head <*> tail $ interim appends the first item of our list (x) to the sublist at head (it has to be there whatever the case) and gloriously present the solution.
Edit: So investigating the [0,1,0,1] resulting [[0,1],[0],[1]] problem that #Jonas Duregård discovered, we can conclude that in the result there shall be no sub lists with a length of 1 except for the last one when singled out. I mean for an input like [0,1,0,1,0,1,0] the above code produces [[0,1],[0],[1],[0],[1],[0]] while it should [[0,1],[0,1],[0,1],[0]]. So I believe adding a squeeze function at the very last stage should correct the logic.
import Data.List (groupBy)
splitSort :: Ord a => [a] -> [[a]]
splitSort [] = []
splitSort [x] = [[x]]
splitSort (x:xs) = squeeze $ (:) <$> (x :) . head <*> tail $ interim
where
pattern = zipWith compare <$> init <*> tail
tuples = zipWith (,) <$> tail <*> pattern
groups = groupBy (\p c -> snd p == snd c) $ tuples (x:xs)
interim = groups >>= return . map fst
squeeze [] = []
squeeze [y] = [y]
squeeze ([n]:[m]:ys) = [n,m] : squeeze ys
squeeze ([n]:(m1:m2:ms):ys) | compare n m1 == compare m1 m2 = (n:m1:m2:ms) : squeeze ys
| otherwise = [n] : (m1:m2:ms) : squeeze ys
squeeze (y:ys) = y : squeeze s
*Main> splitSort [0,1, 0, 1, 0, 1, 0]
[[0,1],[0,1],[0,1],[0]]
*Main> splitSort [5,6,7,2,1,1,1]
[[5,6,7],[2,1],[1,1]]
*Main> splitSort [0,0,1,0,-1]
[[0,0],[1,0,-1]]
Yes; as you will also agree the code has turned out to be a little too lengthy and possibly not so efficient.
The Answer: I have to trust the back of my head when it keeps telling me i am not on the right track. Sometimes, like in this case, the problem reduces down to a single if then else instruction, much simpler than i had initially anticipated.
runner :: Ord a => Maybe Ordering -> [a] -> [[a]]
runner _ [] = []
runner _ [p] = [[p]]
runner mo (p:q:rs) = let mo' = Just (compare p q)
(s:ss) = runner mo' (q:rs)
in if mo == mo' || mo == Nothing then (p:s):ss
else [p] : runner Nothing (q:rs)
splitSort :: Ord a => [a] -> [[a]]
splitSort = runner Nothing
My test cases
*Main> splitSort [0,1, 0, 1, 0, 1, 0]
[[0,1],[0,1],[0,1],[0]]
*Main> splitSort [5,6,7,2,1,1,1]
[[5,6,7],[2,1],[1,1]]
*Main> splitSort [0,0,1,0,-1]
[[0,0],[1,0,-1]]
*Main> splitSort [1,2,3,5,2,0,0,0,-1,-1,0]
[[1,2,3,5],[2,0],[0,0],[-1,-1],[0]]
For this solution I am making the assumption that you want the "longest rally". By that I mean:
splitSort [0, 1, 0, 1] = [[0,1], [0,1]] -- This is OK
splitSort [0, 1, 0, 1] = [[0,1], [0], [1]] -- This is not OK despite of fitting your requirements
Essentially, There are two pieces:
Firstly, split the list in two parts: (a, b). Part a is the longest rally considering the order of the two first elements. Part b is the rest of the list.
Secondly, apply splitSort on b and put all list into one list of list
Taking the longest rally is surprisingly messy but straight. Given the list x:y:xs: by construction x and y will belong to the rally. The elements in xs belonging to the rally depends on whether or not they follow the Ordering of x and y. To check this point, you zip every element with the Ordering is has compared against its previous element and split the list when the Ordering changes. (edge cases are pattern matched) In code:
import Data.List
import Data.Function
-- This function split the list in two (Longest Rally, Rest of the list)
splitSort' :: Ord a => [a] -> ([a], [a])
splitSort' [] = ([], [])
splitSort' (x:[]) = ([x],[])
splitSort' l#(x:y:xs) = case span ( (o ==) . snd) $ zip (y:xs) relativeOrder of
(f, s) -> (x:map fst f, map fst s)
where relativeOrder = zipWith compare (y:xs) l
o = compare y x
-- This applies the previous recursively
splitSort :: Ord a => [a] -> [[a]]
splitSort [] = []
splitSort (x:[]) = [[x]]
splitSort (x:y:[]) = [[x,y]]
splitSort l#(x:y:xs) = fst sl:splitSort (snd sl)
where sl = splitSort' l
I wonder whether this question can be solve using foldr if splits and groups a list from
[5,6,7,2,1,1,1]
to
[[5,6,7],[2,1],[1,1]]
instead of
[[5,6,7],[2],[1,1,1]]
The problem is in each step of foldr, we only know the sorted sub-list on right-hand side and a number to be processed. e.g. after read [1,1] of [5,6,7,2,1,1,1] and next step, we have
1, [[1, 1]]
There are no enough information to determine whether make a new group of 1 or group 1 to [[1,1]]
And therefore, we may construct required sorted sub-lists by reading elements of list from left to right, and why foldl to be used. Here is a solution without optimization of speed.
EDIT:
As the problems that #Jonas Duregård pointed out on comment, some redundant code has been removed, and beware that it is not a efficient solution.
splitSort::Ord a=>[a]->[[a]]
splitSort numList = foldl step [] numList
where step [] n = [[n]]
step sublists n = groupSublist (init sublists) (last sublists) n
groupSublist sublists [n1] n2 = sublists ++ [[n1, n2]]
groupSublist sublists sortedList#(n1:n2:ns) n3
| isEqual n1 n2 = groupIf (isEqual n2 n3) sortedList n3
| isAscen n1 n2 = groupIfNull isAscen sortedList n3
| isDesce n1 n2 = groupIfNull isDesce sortedList n3
| otherwise = mkNewGroup sortedList n3
where groupIfNull check sublist#(n1:n2:ns) n3
| null ns = groupIf (check n2 n3) [n1, n2] n3
| otherwise = groupIf (check (last ns) n3) sublist n3
groupIf isGroup | isGroup = addToGroup
| otherwise = mkNewGroup
addToGroup gp n = sublists ++ [(gp ++ [n])]
mkNewGroup gp n = sublists ++ [gp] ++ [[n]]
isEqual x y = x == y
isAscen x y = x < y
isDesce x y = x > y
My initial thought looks like:
ordruns :: Ord a => [a] -> [[a]]
ordruns = foldr extend []
where
extend a [ ] = [ [a] ]
extend a ( [b] : runs) = [a,b] : runs
extend a (run#(b:c:etc) : runs)
| compare a b == compare b c = (a:run) : runs
| otherwise = [a] : run : runs
This eagerly fills from the right, while maintaining the Ordering in all neighbouring pairs for each sublist. Thus only the first result can end up with a single item in it.
The thought process is this: an Ordering describes the three types of subsequence we're looking for: ascending LT, equal EQ or descending GT. Keeping it the same every time we add on another item means it will match throughout the subsequence. So we know we need to start a new run whenever the Ordering does not match. Furthermore, it's impossible to compare 0 or 1 items, so every run we create contains at least 1 and if there's only 1 we do add the new item.
We could add more rules, such as a preference for filling left or right. A reasonable optimization is to store the ordering for a sequence instead of comparing the leading two items twice per item. And we could also use more expressive types. I also think this version is inefficient (and inapplicable to infinite lists) due to the way it collects from the right; that was mostly so I could use cons (:) to build the lists.
Second thought: I could collect the lists from the left using plain recursion.
ordruns :: Ord a => [a] -> [[a]]
ordruns [] = []
ordruns [a] = [[a]]
ordruns (a1:a2:as) = run:runs
where
runs = ordruns rest
order = compare a1 a2
run = a1:a2:runcontinuation
(runcontinuation, rest) = collectrun a2 order as
collectrun _ _ [] = ([], [])
collectrun last order (a:as)
| order == compare last a =
let (more,rest) = collectrun a order as
in (a:more, rest)
| otherwise = ([], a:as)
More exercises. What if we build the list of comparisons just once, for use in grouping?
import Data.List
ordruns3 [] = []
ordruns3 [a] = [[a]]
ordruns3 xs = unfoldr collectrun marked
where
pairOrder = zipWith compare xs (tail xs)
marked = zip (head pairOrder : pairOrder) xs
collectrun [] = Nothing
collectrun ((o,x):xs) = Just (x:map snd markedgroup, rest)
where (markedgroup, rest) = span ((o==).fst) xs
And then there's the part where there's a groupBy :: (a -> a -> Bool) -> [a] -> [[a]] but no groupOn :: Eq b => (a -> b) -> [a] -> [[a]]. We can use a wrapper type to handle that.
import Data.List
data Grouped t = Grouped Ordering t
instance Eq (Grouped t) where
(Grouped o1 _) == (Grouped o2 _) = o1 == o2
ordruns4 [] = []
ordruns4 [a] = [[a]]
ordruns4 xs = unmarked
where
pairOrder = zipWith compare xs (tail xs)
marked = group $ zipWith Grouped (head pairOrder : pairOrder) xs
unmarked = map (map (\(Grouped _ t) -> t)) marked
Of course, the wrapper type's test can be converted into a function to use groupBy instead:
import Data.List
ordruns5 [] = []
ordruns5 [a] = [[a]]
ordruns5 xs = map (map snd) marked
where
pairOrder = zipWith compare xs (tail xs)
marked = groupBy (\a b -> fst a == fst b) $
zip (head pairOrder : pairOrder) xs
These marking versions arrive at the same decoration concept Jonas Duregård applied.

Haskell, print modified list values with map

I have written the following code, which should take a list of values and print only the values > average, modifying them as val - avg.
For example printModVal [9,0,6] should print 4 1, one element per line, using System.IO print function.
import Data.List
import System.IO
printModVal :: [Float] -> IO ()
printModVal xs = ???
where
average = (foldr (+) 0 xs) / genericLength xs
--use map here and print the values > average as value-average
modVal :: Float -> Float -> Float
modVal x y = x - y
mapVal :: (a->b) -> [a] -> [b]
mapVal f [] = []
mapVal f (x:xs) = f x : mapVal f xs
I would like to know how, at this point, how can I use mapVal (with modVal as mapping function) inside the function printModVal, in order to print the values > 0 (once modified by the mapping function).
Thank you.
You have to apply a filter.
Either to the resulting list
printModVal xs = mapM_ print $ filter (> 0) (mapVal (\x -> modVal x average) xs)
where
average = (foldr (+) 0 xs) / genericLength xs
or to the incoming list
printModVal xs = mapM_ print $ mapVal (\x -> modVal x average) (filter (> average) xs)
where
average = (foldr (+) 0 xs) / genericLength xs
map does never change the length of the list it processes.
Any function with the signature (a->b)->[a]->[b] is very limited in what it can do due to parametricity.

Set builder notation error for my own zip implementation

So I'm learning haskell right now, and I'm having trouble understanding what I'm doing wrong for the following function that emulates zip
1.ziplike xs ys = [(x,y)|c<-[0..(min (length xs) (length ys))-1],x<-xs!!c,y<-ys!!c]
2.ziplike xs ys = [(xs!!c,ys!!c)|c<-[0..(min (length xs) (length ys))-1]]
Now, I know that the correct answer is number 2, but I don't understand why number 1 is wrong for the call ziplike [1,2,3] ['a', 'b', 'c', 'd']. I THINK it's because it's trying to select the index for an individual char, but I'm not sure why.
The error is "Couldn't match expected type ‘[t1]’ with actual type ‘Char’"
To a first approximation:
If e::[a],
and x <- e appears to the right of the | in a list comprehension,
then x :: a wherever it is bound.
This leads to a bit of a problem in your case. You have ys :: [Char] and c :: Int, so that ys!!c :: Char. Hence:
We have ys!!c :: Char
and y <- ys!!c appears to the right of the | in a list comprehension,
so y :: ??? wherever it is bound.
But now we are stuck when trying to write the conclusion about what type y should have: Char is not a list of as, no matter what a we pick.
There are several possible fixes; one is to use let instead of <-, as in
ziplike xs ys = [(x,y)|c<-[0..min (length xs) (length ys)-1],let x=xs!!c; y=ys!!c]
It's a type error.
When you write "x from xs get-index c" (i.e. x <- xs !! c) the thing that you are getting "from" xs !! c is not necessarily a list. It's a technical detail, but it's important. The "from" arrow comes from monad syntax/do-notation. A list comprehension is actually just a do-expression specialized to the List monad; so the right hand side of an arrow <- needs to be a list in the List monad.
You can fix this, first off, by "cheating" with singleton lists, a la:
ziplike xs ys = [ (x,y) | c <- [0 .. min (length xs) (length ys) - 1],
x <- [xs !! c],
y <- [ys !! c]]
So these left-arrows are not "let" variable bindings, but they make Cartesian products: but the Cartesian product of n things with 1 thing with 1 thing is just n * 1 * 1 == n things. So this is great, if a little weird and possibly inefficient.
To do what you were trying to do (bind x and y inside of the list comprehension) you could also write something like:
ziplike xs ys = [let x = xs !! c; y = ys !! c in (x, y)
| c <- [0 .. min (length xs) (length ys) - 1]]
-- or --
ziplike xs ys = [(x, y)
| c <- [0 .. min (length xs) (length ys) - 1],
let x = xs !! c, let y = ys !! c]
-- or --
ziplike xs ys = [(x, y)
| c <- [0 .. min (length xs) (length ys) - 1],
let x = xs !! c; y = ys !! c]
Notice that these are all do-notation ideas tacked together with commas. Of course all of these look more clumsy than
ziplike xs ys = [(xs !! c, ys !! c) | c <- [0..min (length xs) (length ys) - 1]
which does the exact same thing.
With that said, all of this stuff is much more inefficient than the zip function's recursive character: if I double the size of the list, your implementations take 4 times as long to process the whole list; zip only takes twice as long. So be mindful of this "hidden O(n2) factor" in your programming.

Resources