Haskell- Encipher function - haskell

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

Related

In filterM, why is `return (if b then x:ys else ys)` evaluated once after all the lists are created?

filterM :: Monad m => (a -> m Bool) -> [a] -> m [a]
filterM p [] = return []
filterM p (x:xs) = do b <- p x
ys <- filterM p xs
return (if b then x:ys else ys)
and
> filterM (\x -> [True,False]) [1,2,3]
[[1,2,3],[1,2],[1,3],[1],[2,3],[2],[3],[]]
Is return (if b then x:ys else ys) evaluated each time a list is created? Is yes, why isn't the result [[1,2,3]],[[1,2]],[[1,3]],[[1]],[[2,3]],[[2]],[[3]],[[]]?
Does the result [[1,2,3],[1,2],[1,3],[1],[2,3],[2],[3],[]] imply that return (if b then x:ys else ys) is evaluated once after all the lists are created?
In short: because the bind function (>>=) for the instance Monad [] is implement with concatMap, not map.
We can desugar the do block as:
filterM :: Monad m => (a -> m Bool) -> [a] -> m [a]
filterM p [] = return []
filterM p (x:xs) = p x >>= \b -> (filterM p xs >>= \ys -> return (if b then x:ys else ys))
For m ~ [], the >>= function is equivalent to flip concatMap, and return x is equivalent to [x], so that means that we can transform this, for a list, into:
filterM :: (a -> [Bool]) -> [a] -> [[a]]
filterM p [] = [[]]
filterM p (x:xs) = concatMap (\b -> concatMap (\ys -> [if b then (x:ys) else ys]) (filterM p xs)) (p x)
A concatMap (\x -> [f x]) is equivalent to map f, since the concatenation of all these singleton lists will result in a list that contains the outcomes of f for all elements in the given list.
It thus means that the above function is equivalent to:
filterM :: (a -> [Bool]) -> [a] -> [[a]]
filterM p [] = [[]]
filterM p (x:xs) = concatMap (\b -> map (\ys -> if b then (x:ys) else ys) (filterM p xs)) (p x)
If p is \_ -> [True, False], it thus means we can replace (p x) with [True, False], and thus obtain:
concatMap (\b -> map (\ys -> if b then (x:ys) else ys) (filterM p xs)) [True, False]
This thus means that concatMap is the concatenation of two lists: one where b is True, and one where b is False, like:
map (\ys -> (x:ys)) (filterM p xs) ++ map (\ys -> ys) (filterM p xs)
The first map will thus prepend all the lists from filterM p xs with x whereas the second one will not. The above expression is thus equivalent to:
map (x:) (filterM p xs) ++ filterM p xs
if filterM p xs contains the powerset of xs, then the above expression will thus contain the powerset of (x:xs).

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]

Define functions with foldl foldr

I understand the definitions of foldl, foldr, but I have problems with functions defined by them.
For example map with foldr:
map f [] = []
map f l = foldr (\x xs -> f x : xs) [] l
I don't understand the (\x xs -> f x : xs). It is the map function, which foldr takes? But shouldn't it be (\x xs -> f x : f xs), because map f (x:xs) = f x : map f xs?
Example with foldl:
concat (x:xs) = x ++ concat xs
concat' xs = foldl (++) [] xs
concat'' xs = foldl (\ys y -> ys ++ y) [] xs
Of course I understand (++), but what's the logic behind (\ys y -> ys ++ y)? Is it ys = [] and y = xs?
So the function takes [] as ys and y is the first element of xs and concates the [] with the y?
Concrete example:
concat'' [1,2,3] = foldl (\ys y -> ys ++ y) [] [1,2,3]
=> foldl (\ys y -> ys ++ y) ((\ys y -> ys ++ y) [] [1]) [2,3]
=> foldl (\ys y -> ys ++ y) [1] [2,3]
=> foldl (\ys y -> ys ++ y) ((\ys y -> ys ++ y) [1] [2]) [3]
=> foldl (\ys y -> ys ++ y) [1,2] [3]
=> foldl (\ys y -> ys ++ y) ((\ys y -> ys ++ y) [1,2] [3]) []
=> foldl (\ys y -> ys ++ y) [1,2,3] []
=> [1,2,3]
Another thing: concat only takes 1 list xs, so if I want to concat 2 lists?
concat (x:xs) ys = x ++ concat xs ys
concat [1,2,3] [4,5,6] with foldl?
Reverse:
reverse (x:xs) = reverse xs ++ [x]
reverse' l = foldl (\xs x -> [x] : xs) [] l
reverse'' l = foldr (\x xs -> xs ++ [x]) [] l
The foldr is intuitive clear (with the questions from above), but what's behind the reverse order in foldl (\xs x -> [x] : xs)? This foldl (\x xs -> xs ++ [x]) [] l would be wrong, wouldn't it?
Thanks a lot!
The code
foldr (\x xs -> ...) end list
could be read, roughly, as follows
scan the whole list
if it's empty, just return end end
otherwise:
let x be the element at hand
let xs be the rest of the list, after having been processed
apply the ... operation
The emphasized part is crucial. xs is not the rest of the list, but the result of the "recursive call" on it.
Indeed, xs is a bad name for that. In thee general case, it's not even a list! E.g. one would never write (silly example)
foldr (\x xs -> x + xs) 0 [1..100] -- sum 1..100
but rather prefer something like
foldr (\x partialSum -> x + partialSum) 0 [1..100] -- sum 1..100
(Actually, one would not sum using foldr, but let's leave that aside.)
So, just read it like this:
map f l = foldr (\x mappedTail -> f x : mappedTail) [] l

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.

Haskell pair and unpair functions

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])

Resources