Haskell: Pattern Matching with Lists - list

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

Related

Count non-empty lists in a lists of lists

I am trying to count the number of non-empty lists in a list of lists with recursive code.
My goal is to write something simple like:
prod :: Num a => [a] -> a
prod [] = 1
prod (x:xs) = x * prod xs
I already have the deifniton and an idea for the edge condition:
nonEmptyCount :: [[a]] -> Int
nonEmptyCount [[]] = 0
I have no idea how to continue, any tips?
I think your base case, can be simplified. As a base-case, we can take the empty list [], not a singleton list with an empty list. For the recursive case, we can consider (x:xs). Here we will need to make a distinction between x being an empty list, and x being a non-empty list. We can do that with pattern matching, or with guards:
nonEmptyCount :: [[a]] -> Int
nonEmptyCount [] = 0
nonEmptyCount (x:xs) = -- …
That being said, you do not need recursion at all. You can first filter your list, to omit empty lists, and then call length on that list:
nonEmptyCount :: [[a]] -> Int
nonEmptyCount = length . filter (…)
here you still need to fill in ….
Old fashion pattern matching should be:
import Data.List
nonEmptyCount :: [[a]] -> Int
nonEmptyCount [] = 0
nonEmptyCount (x:xs) = if null x then 1 + (nonEmptyCount xs) else nonEmptyCount xs
The following was posted in a comment, now deleted:
countNE = sum<$>(1<$)<<<(>>=(1`take`))
This most certainly will look intimidating to the non-initiated, but actually, it is equivalent to
= sum <$> (1 <$) <<< (>>= (1 `take`))
= sum <$> (1 <$) . (take 1 =<<)
= sum . fmap (const 1) . concatMap (take 1)
= sum . map (const 1) . concat . map (take 1)
which is further equivalent to
countNE xs = sum . map (const 1) . concat $ map (take 1) xs
= sum . map (const 1) $ concat [take 1 x | x <- xs]
= sum . map (const 1) $ [ r | x <- xs, r <- take 1 x]
= sum $ [const 1 r | (y:t) <- xs, r <- take 1 (y:t)] -- sneakiness!
= sum [const 1 r | (y:_) <- xs, r <- [y]]
= sum [const 1 y | (y:_) <- xs]
= sum [ 1 | (_:_) <- xs] -- replace each
-- non-empty list
-- in
-- xs
-- with 1, and
-- sum all the 1s up!
= (length . (take 1 =<<)) xs
= (length . filter (not . null)) xs
which should be much clearer, even if in a bit sneaky way. It isn't recursive in itself, yes, but both sum and the list-comprehension would be implemented recursively by a given Haskell implementation.
This reimplements length as sum . (1 <$), and filter p xs as [x | x <- xs, p x], and uses the equivalence not (null xs) === (length xs) >= 1.
See? Haskell is fun. Even if it doesn't yet feel like it, but it will be. :)

how to rewrite code using tail recursion

I just looking for a little advice, how to rewrite code using tail recursion
open Core.Std;;
let rec dig x =
match x with
| 0 -> []
| _ -> x :: dig (x - 1)
;;
let () =
let numbers = dig 10 in
List.iter ~f:(Printf.printf "%d, ") numbers;
Printf.printf "\n";
;;
Any advice will be helpful
let dig x =
let rec f x s =
match x with
| 0 -> s
| _ -> f (x-1) (x::s)
f x []
Is this what you want? It's using tail recursion.
Edit:
for a decreasing seq, just replace (x::s) with (List.append s [x]) or (s # [x]) but it's NOT a good idea,and List.rev is better:
let dig x =
let rec f x s =
match x with
| 0 -> s
| _ -> f (x-1) (s # [x])
f x []
let dig x =
let rec f s z =
if z = x then s
else f (z::s) (z+1)
in
f [] 0
not sure if this floats your boat: You may have to tweak the border cases depending if you want 0 or the starting number included.
If you don't want to use List.rev after building the list backwards (which in my opinion is perfectly fine), nor starting your recursion with 0 instead of n, you can use some kind of continuation:
let dig2 x =
let rec aux x kont =
match x with
| 0 -> kont
| _ -> aux (x-1) (fun l -> kont (x::l))
in
aux x (fun l -> l) [];;
Basically each step returns a function that, given the list built by the remaining steps, will append x to it. We start the recursion with the identity function since we don't have anything to build yet. Then, when we exit from the recursion, we thus just have to apply the empty list to the obtained function.
Well, it seems to can have multiple solutions
open Core.Std;;
let rec digtail ?(l=[]) x =
match x with
| 0 -> l
| _ -> digtail ~l: (l # [x]) (x - 1)
;;
let () =
let numbers = digtail 10 in
List.iter ~f:(Printf.printf "%d, ") numbers;
Printf.printf "\n";
;;
Thanks to all, you helped a lot.

How to add values from two lists (+extra condition) in Haskell

I got a problem with this exercise. I've been trying to solve it for a long time searching for stuff, but I am unable to.
Define functions:
addLnat :: [Int] -> [Int] -> [Int]
mulLnat :: [Int] -> [Int] -> [Int]
addLnat adds numbers from two arrays eg.
addLnat [4,5,6] [8,5,2] -> [2,1,9]
as [4+8 gives 2 carry 1, 5+5+1 gives 1 carry 1, 6+2+1 = 9]
Lnat, is a "list natural number", represented as a list of base-10 digits, least significant first. So the number 654 is [4,5,6].
What I got is:
addLnat :: [Int] -> [Int] -> [Int]
addLnat _ [] = []
addLnat [] _ = []
addLnat (x:xs) (y:ys) = (if (x+y) > 9 then x+y-10 else (x+y)):(addLnat xs ys)
I adding number and ignoring carry. Not sure how to solve it.
Any help would be much appreciated.
I have improved the solution as per user5402 comment, so created addLnat' cr xs ys, but when I what to pass carry as a parameter it fails to load - most probable that I am getting the syntax wrong:(
(cr is 0 only for now and it will be replaced by maths).
addLnat' c (x:xs) (y:ys) = d : addLnat' cr xs ys
where d = if c+x+y < 9 then x+y else c+x+y-((quot (c+x+y) 10)*10)
cr = 0
Any ideas?
I am not very good at haskell but maybe this can help ;
add::[Int]->[Int]->[Int]
add x y = add' 0 x y
There we define a function add that will use add' to add two lists The main idea is to "save" carry and carefully work with corner cases. Here carry is saved in "variable" rest
add'::Int->[Int]->[Int]->[Int]
add' 0 x [] = x
add' rest (x:[]) (y:[]) = [(r `mod` 10),(r `div` 10)]
where r = x+y+rest
add' y (x:xs) [] = add' (r `div` 10) ((r `mod` 10):xs) []
where r = x+y
add' rest (x:xs) (y:ys) = (r `mod` 10) : (add' (r `div` 10) xs ys)
where r = x+y+rest
List x must be bigger than list y but that's not a problem
add [5,7,8] [4,3,2] => [9,0,1,1] (correct)
add [1,2,3] [4,5,6] => [5,7,9,0] (correct)
You need to write a version of addLnat which accepts a carry parameter:
addLnat' c (x:xs) (y:ys) = d : addLnat c' xs ys
where d = if c+x+y > 9 then ... else ...
c' = ... the next carry bit ...
There are a lot more details and corner cases to consider, but this is the basic idea.
Finally,
addLnat xs ys = addLnat' 0 xs ys -- initially the carry is 0

Haskell <<loop>>

With getIndex xs y I want the index of the first sublist in xs whose length is greater than y.
The output is:
[[],[4],[4,3],[3,5,3],[3,5,5,6,1]]
aufgabe6: <<loop>>
why getIndex does not work?
import Data.List
-- Die Sortierfunktion --
myCompare a b
| length a < length b = LT
| otherwise = GT
sortList :: [[a]] -> [[a]]
sortList x = sortBy myCompare x
-- Die Indexfunktion --
getIndex :: [[a]] -> Int -> Int
getIndex [] y = 0
getIndex (x:xs) y
| length x <= y = 1 + getIndex xs y
| otherwise = 0
where (x:xs) = sortList (x:xs)
main = do
print (sortList [[4],[3,5,3],[4,3],[3,5,5,6,1],[]])
print (getIndex [[4],[3,5,3],[4,3],[3,5,5,6,1],[]] 2)
Getting it to terminate
The problem is in this case
getIndex (x:xs) y
| length x <= y = 1 + getIndex xs y
| otherwise = 0
where (x:xs) = sortList (x:xs)
You're confusing which (x:xs) is which. You should instead do
getIndex zs y
| length x <= y = 1 + getIndex xs y
| otherwise = 0
where (x:xs) = sortList zs
giving
Main> main
[[],[4],[4,3],[3,5,3],[3,5,5,6,1]]
3
*Main> getIndex [[],[2],[4,5]] 1
2
*Main> getIndex [[],[2],[4,5]] 5
3
This gives you the number of the first list of length at least y in the sorted list, which actually answers the question "How many lists are of length at most y in the original?"
How can we find out other facts?
If you want position from the original list, you can tag the entries with their position, using zip:
*Main> zip [1..] [[4],[3,5,3],[4,3],[3,5,5,6,1],[]]
[(1,[4]),(2,[3,5,3]),(3,[4,3]),(4,[3,5,5,6,1]),(5,[])]
Let's make a utility function for working with those:
hasLength likeThis (_,xs) = likeThis (length xs)
We can use it like this:
*Main> hasLength (==4) (1,[1,2,3,4])
True
*Main> filter (hasLength (>=2)) (zip [1..] ["","yo","hi there","?"])
[(2,"yo"),(3,"hi there")]
Which means it's now easy to write a function that gives you the index of the first list of length longer than y:
whichIsLongerThan xss y =
case filter (hasLength (>y)) (zip [1..] xss) of
[] -> error "nothing long enough" -- change this to 0 or (length xss + 1) if you prefer
(x:xs) -> fst x
This gives us
*Main> whichIsLongerThan [[4],[3,5,3],[4,3],[3,5,5,6,1],[]] 2
2
*Main> whichIsLongerThan [[4],[3,5,3],[4,3],[3,5,5,6,1],[]] 3
4
*Main> whichIsLongerThan [[4],[3,5,3],[4,3],[3,5,5,6,1],[]] 0
1
Shorter?
but we can do similar tricks:
whichIsShorterThan xss y =
case filter (hasLength (<y)) (zip [1..] xss) of
[] -> error "nothing short enough" -- change this to 0 or (length xss + 1) if you prefer
(x:xs) -> fst x
so you get
*Main> whichIsShorterThan [[4],[3,5,3],[4,3],[3,5,5,6,1],[]] 2
1
*Main> whichIsShorterThan [[4],[3,5,3],[4,3],[3,5,5,6,1],[]] 1
5
*Main> whichIsShorterThan [[4],[3,5,3],[4,3],[3,5,5,6,1],[]] 0
*** Exception: nothing short enough
Generalised
Let's pull out the common theme there:
whichLength :: (Int -> Bool) -> [[a]] -> Int
whichLength likeThis xss =
case filter (hasLength likeThis) (zip [1..] xss) of
[] -> error "nothing found" -- change this to 0 or (length xss + 1) if you prefer
(x:xs) -> fst x
so we can do
*Main> whichLength (==5) [[4],[3,5,3],[4,3],[3,5,5,6,1],[]]
4
*Main> whichLength (>2) [[4],[3,5,3],[4,3],[3,5,5,6,1],[]]
2
Do you mean index of the firs sublist with length > y? If that's not the goal (and < y is), then
length x <= y = 1 + getIndex xs y
should be
length x >= y = 1 + getIndex xs y
Also, (x:xs) = sortList (x:xs) is bottom, since it will never end. If you want to sort it somehow, you might follow AndrewC's solution.
let (and where) bindings in Haskell are recursive: LHS and RHS both belong (and thus refer to) to the same new scope. Your code is equivalent to
........
getIndex (x:xs) y =
let -- new, extended scope, containing definitions for
(x:xs) = a -- new variables x, xs, a ... the original vars x, xs
a = sortList a -- are inaccessible, __shadowed__ by new definitions
in -- evaluated inside the new, extended scope
if length x <= y -- x refers to the new definition
then 1 + getIndex xs y
else 0
When the value of x is demanded by length, its new definition (x:xs) = a demands the value of a, which is directly defined in terms of itself, a = sortList a:
a = sortList a
= sortList (sortList a)
= sortList (sortList (sortList a))
= sortList (sortList (sortList (sortList a)))
= ....
A black hole.

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]