Haskell pair and unpair functions - haskell

I have the following two functions written.
pair :: [a] -> [(a, a)]
pair [] = []
pair [x] = []
pair (x1:x2:xs) = (x1, x2) : pair xs
unpair :: [(a, a)] -> [a]
unpair [] = []
unpair ((x1, x2):xs) = x1 : x2 : unpair xs
Pair will take pairs of elements and make 2-tuples of them. If the list has an odd number of elements, discard the last one. Unpair is the reverse of pair.
These work, but wondering whether there is a more succinct way to write these.

One-liners:
pair xs = map snd . filter fst . zip (iterate not True) $ zip xs (drop 1 xs)
unpair = concatMap (\(x,y) -> [x,y])
You could have also abbreviate your definition of pair a little:
pair (x1:x2:xs) = (x1, x2) : pair xs
pair _ = []

It's not any more concise, but for the sake of clarity I'd use splitEvery from Data.List.Split for pair:
pair = map tuplify . filter ((>1) . length) . splitEvery 2
where
tuplify [x, y] = (x, y)
This is off the top of my head—it would be nicer to check the length of the last list only.
For unpair I'd use foldr to avoid the explicit recursion:
unpair = foldr (\(x, y) -> (x:) . (y:)) []
This is just a matter of taste.

So many possibilities. How about these?
unpair' = concatMap (\(x,y) -> [x,y])
pair' xs = map snd . filter fst . zip (cycle [True, False]) $ zip xs (tail xs)
pair'' xs = [(x,y) | (True,x,y) <- zip3 (cycle [True,False]) xs (tail xs)]
The two versions of pair should be the same.
Edit: Regarding my comment above, one can use the split package from Hackage to write:
pair xs = map head . splitEvery 2 $ zip xs (tail xs)
which is closer to the desired
pair xs = everyOther $ zip xs (tail xs)
But, in the spirit of pointlessness, I think we should probably all agree on writing it,
pair = map head . splitEvery 2 . (zip <$> id <*> tail)
to ensure confusion.

pair s = dropEven $ zip s (tail s)
where dropEven s = map fst $ filter snd $ zip s (cycle [True, False])
unpair = concatMap (\(a, b) -> [a, b])
Though I definitely prefer your definition of pair.

This is a nice use for view patterns:
{-# LANGUAGE ViewPatterns #-}
pair :: [a] -> [(a,a)]
pair (splitAt 2 -> ([x,y],ys)) = (x,y) : pair ys
pair _ = []
unpair :: [(a,a)] -> [a]
unpair = (>>= \(x,y) -> [x,y])

Related

Haskell- Encipher function

I am creating function encipher in HASKELL. This is what I have so far.
encipher :: Eq a => [a] -> [b] -> [a] -> [b]
encipher _ _ [] = []
encipher xs ys (z:zs) = if f == []
then z:encipher xs ys zs
else snd (head f) : (encipher xs ys zs)
where t = zip xs ys
f = filter ((== z) . fst) t
p9tests = [encipher ['A'..'Z'] ['a'..'z'] "THIS" == "this"]
where I test it with p9tests. Not sure what I am doing wrong.
Your problem is indentation. All definitions under where need to be indented at the same level.
So to fix your particular error, you could indent f to the level of t on the line above:
where t = zip xs ys
f = filter ((== z) . fst) t
Or you could go the other way and bring t to f's level:
where
t = zip xs ys
f = filter ((== z) . fst) t

ConcatMap in haskell without ++

I'm trying to write the code for Haskell concatmap without using the ++ operator where
concatMap :: (a -> [b]) -> [a] -> [b]
and producing the same result of
concatMap f = foldr ((++) . f) []
I'm quite new to Haskell and this was just an exercise I found. Actually, I do not even know if this can be done.
Here's a way that makes the state of the computation explicit:
concatMap :: (a -> [b]) -> [a] -> [b]
concatMap f = go []
where
-- We have b values; use one.
go (b:bs) as = b : go bs as
-- No bs left; get some more.
go [] (a:as) = go (f a) as
-- Nothing left; we're done.
go [] [] = []
This maintains the current list of bs, filling it up whenever it's empty.
This might be cheating, but how about:
myConcatMap f s = concat (map f s)
The concat function uses some sort of ++ in its source code, so that is why you might not like it. You can try to use an alternative concat that does list comprehensions, it has a more "from scratch" feeling.
myconcat ll = [y | x <- ll, y <- x]
You can use the fact that foldr (:) = flip (++)
concatMap f = foldr (flip (foldr (:)) . f) []
Or pointfree:
concatMap = flip foldr [] . (flip (foldr (:)) .)

Haskell takeWhile + 1

How can I write a takeWhile that would keep the first element that doesn't match the condition?
Example (obviously my example is trickier than this) :
Instead of takeWhile (\× - > x! = 3) [1..10] to return [1,2] I need [1,2,3].
I thought of (takeWhile myFunc myList) ++ [find myFunc myList] but it means I need to go through my list 2 times...
Any idea?
You can use span or break.
λ> span (/=3) [1..10]
([1,2],[3,4,5,6,7,8,9,10])
So you can do something like this:
takeWhileInc :: (a -> Bool) -> [a] -> [a]
takeWhileInc p xs = case zs of [] -> error "not found"
(z:_) -> ys ++ [z]
where
(ys, zs) = span p xs
(Or whatever you want to happen when zs is empty because no 3
was found.)
You can roll your own.
takeWhileOneMore :: (a -> Bool) -> [a] -> [a]
takeWhileOneMore p = foldr (\x ys -> if p x then x:ys else [x]) []
Compare it with
takeWhile :: (a -> Bool) -> [a] -> [a]
takeWhile p = foldr (\x ys -> if p x then x:ys else []) []
Explicit recursion would also be fine for this.
takeWhileOneMore :: (a -> Bool) -> [a] -> [a]
takeWhileOneMore p [] = []
takeWhileOneMore p (x:xs) =
if p x
then x : takeWhileOneMore p xs
else [x]
I like to use the base function more than many people do, such as re-using takeWhile in an intelligent way to get the desired result. For example, you can create a new list of predicates with the first element being True and takeWhile this list is true:
takeWhileP1 p xs = map snd (takeWhile fst (zip (True:map p xs) xs)
This generalizes nicely as well (not necessarily efficient in this form):
takeWhilePlusN n p xs = map snd (takeWhile fst (zip (replicate n True ++ map p xs) xs))
Or perhaps easier to read:
takeWhilePlusN n p xs =
let preds = replicate n True ++ map p xs
annotated = zip preds xs
in map snd (takeWhile fst annotated)
And the result:
*Main> takeWhilePlusN 3 (<5) [1..10]
[1,2,3,4,5,6,7]
*Main> takeWhilePlusN 1 (<5) [1..10]
[1,2,3,4,5]
*Main> takeWhileP1 (<5) [1..10]
[1,2,3,4,5]
*Main> takeWhile (<5) [1..10]
[1,2,3,4]
When the condition fails for a element, instead of terminating with empty list, we can return the element.
takeWhileInclusive :: (a->Bool) -> [a] -> [a]
takeWhileInclusive _ [] = []
takeWhileInclusive predicate (x:xs) = if predicate x
then do (x: takeWhileInclusive predicate xs)
else [x]

Haskell - How can I make this lists into tuple function pair with all elements?

So i have
pair:: [a] -> [b] -> [(a,b)]
pair[] _ = []
pair(x:xs) (y:ys) = (x, y) : prod xs ys
But the result are only like the following:
>> pair [1,2] [3,4]
>> [(1,3),(2,4)]
How can I make this so it pairs like:
[(1,3),(1,4),(2,3),(2,4)]
You can use the list applicative (or monad) instance:
λ> liftA2 (,) [1,2] [3,4]
[(1,3),(1,4),(2,3),(2,4)]
Or, equivalently,
f = do
x <- [1,2]
y <- [3,4]
return (x,y)
You can also use a list comprehension:
[ (x,y) | x <- [1,3], y <- [2,4] ]
Although there is already a much more elegant answer, i think it is worthwhile to show how this would be achieved in a simple straightforward way. If you want to get all pairs, you obviously need to visit every element of one list for an element in the other.
pair :: [a] -> [b] -> [(a, b)]
pair [] _ = []
pair (x:xs) ys = pair' x ys ++ pair xs ys where
pair' :: a -> [b] -> [(a, b)]
pair' _ [] = []
pair' x (y:ys) = (x,y) : pair' x ys
But of course using the pair = liftA2 (,) or [1,3] >>= \x -> [2,4] >>= \y -> (x,y) in its do notation or list comprehension notation is much better. Also ++ isn't what you normally want to do. So maybe you can build the lists as pair' would do, keep them in a list and then concat them.
concat $ map (\x -> map (\y -> (x,y)) ys) xs

Ways to pack (adjacent) elements of a list into 2-tuples

I was wondering if there would be a concise/one-liner way to do the following:
pack :: [a] -> [(a, a)]
pack [] = []
pack [_] = []
pack (x:y:xs) = (x, y) : pack xs
Which is the same as:
pack' xs = [(x, y) | (x, y, i) <- zip3 xs (tail xs) [0..], even i]
I don’t have much against either of these two options, but I was wondering: is there more concise way by combining (,) with some other function?
I had assumed there’d be such a way, but it eludes me. So this is just out of curiosity.
Thanks!
We can easily split the list into two lists with alternating elements with this tidbit (due to HaskellWiki)
foldr (\a ~(x,y) -> (a:y,x)) ([],[])
All that remains is to combine the lists with zip
pack :: [a] -> [(a, a)]
pack = uncurry zip . foldr (\a ~(x,y) -> (a:y,x)) ([],[])
Another one-liner using LambdaCase and Data.List.unfoldr:
pack = unfoldr $ \case (x:y:zs) -> Just ((x,y),zs); _ -> Nothing
Something I want occasionally is splits -
splits :: Int -> [a] -> [[a]]
splits n = unfoldr $ \case [] -> Nothing ; xs -> Just $ splitAt n xs
And given that, pack becomes:
pack xs = [ (a,b) | [a,b] <- splits 2 xs ]
Note that for xs = [x1, x2, ..., xn-1, xn], we have
init xs = [x1, x2, ... , xn-1]
tail xs = [x2, x3, ... , xn ]
leading to
zip (init xs) (tail xs) = [(x1, x2), (x2, x3), (x3, x4), ...]
and what we want is
pack xs = [(x1, x2), (x3, x4), ...]
which is easy to get once we have a list of masks
cycle [True, False] = [ True, False, True, ... ]
leading to the one-liner
pack :: [a] -> [(a, a)]
pack xs = map snd . filter fst . zip (cycle [True, False]) $ zip (init xs) (tail xs)
I don't know if this is one line, but:
snd $ foldr (\ x (z, ps) -> maybe (Just x, ps) (\y -> (Nothing, (x, y) : ps) z) (Nothing, []) $ xs
should be the same as your function.

Resources