Turning List Comprehension into Functional Application - haskell

I have a function which was written in list comprehension. As a learning I decided to try to convert this function into a functional application using map, zip, fold, etc. I am having a really hard time converting this particular one.
It might seem unreasonable for what it is doing, but it is part of a bigger function and I want to get this piece working first.
combination :: Int -> [a] -> [([a],[a])]
combination 0 xs = [([],xs)]
combination n (x:xs) = [ (x:ys,zs) | (ys,zs) <- combination (n-1) xs ]

It's just a map:
combination :: Int -> [a] -> [([a],[a])]
combination 0 xs = [([],xs)]
combination n (x:xs) = map (\(ys, zs) -> (x:ys,zs)) (combination (n-1) xs)

Related

Intermediate value in simple Haskell function

I need a function to double every other number in a list. This does the trick:
doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther (x:[]) = [x]
doubleEveryOther (x:(y:zs)) = x : 2 * y : doubleEveryOther zs
However, the catch is that I need to double every other number starting from the right - so if the length of the list is even, the first one will be doubled, etc.
I understand that in Haskell it's tricky to operate on lists backwards, so my plan was to reverse the list, apply my function, then output the reverse again. I have a reverseList function:
reverseList :: [Integer] -> [Integer]
reverseList [] = []
reverseList xs = last xs : reverseList (init xs)
But I'm not quite sure how to implant it inside my original function. I got to something like this:
doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther (x:[]) = [x]
doubleEveryOther (x:(y:zs)) =
| rev_list = reverseList (x:(y:zs))
| rev_list = [2 * x, y] ++ doubleEveryOther zs
I'm not exactly sure of the syntax of a function that includes intermediate values like this.
In case it's relevant, this is for Exercise 2 in CIS 194 HW 1.
This is a very simple combination of the two functions you've already created:
doubleEveryOtherFromRight = reverseList . doubleEveryOther . reverseList
Note that your reverseList is actually already defined in the standard Prelude as reverse. so you didn't need to define it yourself.
I'm aware that the above solution isn't very efficient, because both uses of reverse need to pass through the entire list. I'll leave it to others to suggest more efficient versions, but hopefully this illustrates the power of function composition to build more complex computations out of simpler ones.
As Lorenzo points out, you can make one pass to determine if the list has an odd or even length, then a second pass to actually construct the new list. It might be simpler, though, to separate the two tasks.
doubleFromRight ls = zipWith ($) (cycle fs) ls -- [f0 ls0, f1 ls1, f2 ls2, ...]
where fs = if odd (length ls)
then [(*2), id]
else [id, (*2)]
So how does this work? First, we observe that to create the final result, we need to apply one of two function (id or (*2)) to each element of ls. zipWith can do that if we have a list of appropriate functions. The interesting part of its definition is basically
zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys
When f is ($), we're just applying a function from one list to the corresponding element in the other list.
We want to zip ls with an infinite alternating list of id and (*2). The question is, which function should that list start with? It should always end with (*2), so the starting item is determined by the length of ls. An odd-length requires us to start with (*2); an even one, id.
Most of the other solutions show you how to either use the building blocks you already have or building blocks available in the standard library to build your function. I think it's also instructive to see how you might build it from scratch, so in this answer I discuss one idea for that.
Here's the plan: we're going to walk all the way to the end of the list, then walk back to the front. We'll build our new list during our walk back from the end. The way we'll build it as we walk back is by alternating between (multiplicative) factors of 1 and 2, multiplying our current element by our current factor and then swapping factors for the next step. At the end we'll return both the final factor and the new list. So:
doubleFromRight_ :: Num a => [a] -> (a, [a])
doubleFromRight_ [] = (1, [])
doubleFromRight_ (x:xs) =
-- not at the end yet, keep walking
let (factor, xs') = doubleFromRight_ xs
-- on our way back to the front now
in (3-factor, factor*x:xs')
If you like, you can write a small wrapper that throws away the factor at the end.
doubleFromRight :: Num a => [a] -> [a]
doubleFromRight = snd . doubleFromRight_
In ghci:
> doubleFromRight [1..5]
[1,4,3,8,5]
> doubleFromRight [1..6]
[2,2,6,4,10,6]
Modern practice would be to hide the helper function doubleFromRight_ inside a where block in doubleFromRight; and since the slightly modified name doesn't actually tell you anything new, we'll use the community standard name internally. Those two changes might land you here:
doubleFromRight :: Num a => [a] -> [a]
doubleFromRight = snd . go where
go [] = (1, [])
go (x:xs) = let (factor, xs') = go xs in (3-factor, factor*x:xs')
An advanced Haskeller might then notice that go fits into the shape of a fold and write this:
doubleFromRight :: Num a => [a] -> [a]
doubleFromRight = snd . foldr (\x (factor, xs) -> (3-factor, factor*x:xs)) (1,[])
But I think it's perfectly fine in this case to stop one step earlier with the explicit recursion; it may even be more readable in this case!
If we really want to avoid calculating the length, we can define
doubleFromRight :: Num a => [a] -> [a]
doubleFromRight xs = zipWith ($)
(foldl' (\a _ -> drop 1 a) (cycle [(2*), id]) xs)
xs
This pairs up the input list with the cycled infinite list of functions, [(*2), id, (*2), id, .... ]. then it skips along them both. when the first list is finished, the second is in the appropriate state to be - again - applied, pairwise, - on the second! This time, for real.
So in effect it does measure the length (of course), it just doesn't count in integers but in the list elements so to speak.
If the length of the list is even, the first element will be doubled, otherwise the second, as you've specified in the question:
> doubleFromRight [1..4]
[2,2,6,4]
> doubleFromRight [1..5]
[1,4,3,8,5]
The foldl' function processes the list left-to-right. Its type is
foldl' :: (b -> a -> b) -> b -> [a] -> b
-- reducer_func acc xs result
Whenever you have to work on consecutive terms in a list, zip with a list comprehension is an easy way to go. It takes two lists and returns a list of tuples, so you can either zip the list with its tail or make it indexed. What i mean is
doubleFromRight :: [Int] -> [Int]
doubleFromRight ls = [if (odd i == oddness) then 2*x else x | (i,x) <- zip [1..] ls]
where
oddness = odd . length $ ls
This way you count every element, starting from 1 and if the index has the same parity as the last element in the list (both odd or both even), then you double the element, else you leave it as is.
I am not 100% sure this is more efficient, though, if anyone could point it out in the comments that would be great

How to compare multiple strings within in the same list in Haskell

I am trying to write a Haskell function that takes in a list of strings, compares all the strings in the list, and outputs a list of strings that are of the longest length. I want to do this without any predefined functions or imports, I want to try and figure it out all recursively. For example:
longeststrings["meow","cats","dog","woof"] -> ["meow","cats","woof"]
I know it is a silly example, but I think it proves the point.
I want to do something like
longeststrings:: [string] -> [string]
longeststrings [] = []
longeststrings [x:xs] = if (x > xs) x:longeststrings[xs]
But I don't know how to only take the largest size strings out of the list, or remove the smallest ones. I would appreciate any help.
you could trivially keep track of the longest length string and an accumulator of values of that length.
longestStrings :: [String] -> [String]
longestStrings = go [] 0
where
go acc _ [] = acc -- base case
go acc n (x:xs)
| length x > n = go [x] (length x) xs
-- if x is longer than the previously-seen longest string, then set
-- accumulator to the list containing only x, set the longest length
-- to length x, and keep looking
| length x == n = go (x:acc) n xs
-- if x is the same length as the previously-seen longest string, then
-- add it to the accumulator and keep looking
| otherwise = go acc n xs
-- otherwise, ignore it
or, as Davislor rightly mentions in the comments, this can be implemented as a fold by teaching the helper function to determine its own longest length
longestStrings :: [String] -> [String]
longestStrings = foldr f []
where
f x [] = [x]
f x yss#(y:_) =
case compare (length x) (length y) of
GT -> [x]
EQ -> x : yss
LT -> yss
As requested, here’s a version with and without the use of where. I think this is a good demonstration of why the advice not to use where is bad advice. I think the first version is a lot easier to understand.
Keep in mind, functional programming isn’t a monastic vow to forswear certain keywords out of masochism. Nor is it a checklist of fashion tips (where is so last season!). “You should avoid that construct arbitrarily because it’s not the ‘functional’ thing to do” really is not how it works. So you shouldn’t uglify your code for the sake of a tip like that.
It is often a good idea to follow the same coding style as other programmers so they will find it easier to understand you. (For example, Adam Smith was subtly trying to train you that acc is a common name for an accumulator and go a common name for a recursive helper function, and they help other programmers figure out the pattern he’s using.) But in fact Haskell programmers do use where, a lot.
Anyway, the code:
longeststrings :: [String] -> [String]
{- Filters all strings as long as any other in the list. -}
longeststrings = foldr go []
where
go x [] = [x]
go x leaders | newlength > record = [x]
| newlength == record = x:leaders
| otherwise = leaders
where
record = (length . head) leaders
newlength = length x
longestStringsUsingLambda :: [String] -> [String]
longestStringsUsingLambda = foldr
(\x leaders ->
if leaders == [] then [x]
else case compare (length x) (length $ head leaders) of
GT -> [x]
EQ -> x:leaders
LT -> leaders )
[]
main :: IO ()
main = let testcases = [ ["meow","cats","dog","woof"],
["foo","bar","baz"],
["meep","foo","bar","baz","fritz","frotz"]
]
in foldMap print $
map longestStringsUsingLambda testcases
You can try eliminating the let testcases = ... and see if you consider that an improvement.

How to write a a reverse function in Haskell

So, I know, there is a built in function to reverse a list in Haskell, but I'm trying to write my own little function, just to practice some Haskell. I thought of the following code, which sadly is not working. Could you guys tell me what I did wrong?
rev :: [Int] -> [Int]
rev [] = []
rev [x] = last [x] : rev init [x]
If you want to do it efficiently, I'd recommend you use an accumulator:
rev :: [a] -> [a]
rev xs = go xs []
where
go :: [a] -> [a] -> [a]
go [] ys = ys
go (x:xs) ys = go xs (x:ys)
The function go, at each step, removes one element from the first list xs and prepends it to the second list ys. This is similar to popping from a stack and pushing to another stack -- which reverses the order.
Since we only use a constant amount of time at each recursive call, we get O(n) complexity, where n is the list length.
Instead, if at each recursive call we use last or append with ... ++ [x], we pay O(n) for each call, hence O(n^2) overall.
You almost had it.
rev :: [Int] -> [Int]
rev [] = []
rev x = last x : rev (init x)
Explanation: [x] was a list containing x, whereas you want to operate directly with x
ps. here's the documentation for Data.List. And remember to import Data.List
Well, you could do something like this:
rev :: [Int] -> [Int]
rev [] = []
rev (x:l) = (rev l) ++ [x]
The 3rd line takes the first element from the list and then creates a list containing only that element. This is appended to the result of the recursion rev l call.

How to efficiently generate all lists of length `n^2` containing `n` copies of every `x < n`?

Given an integer n, how can I build the list containing all lists of length n^2 containing exactly n copies of each integer x < n? For example, for n = 2, we have:
[0,0,1,1], [0,1,0,1], [1,0,0,1], [0,1,1,0], [1,0,1,0], [1,1,0,0]
This can be easily done combining permutations and nub:
f :: Int -> [[Int]]
f n = nub . permutations $ concatMap (replicate n) [0..n-1]
But that is way too inefficient. Is there any simple way to encode the efficient/direct algorithm?
Sure, it's not too hard. We'll start with a list of n copies of each number less than n, and repeatedly choose one to start our result with. First, a function for choosing an element from a list:
zippers :: [a] -> [([a], a, [a])]
zippers = go [] where
go l (h:r) = (l,h,r) : go (h:l) r
go _ [] = []
Now we'll write a function that produces all possible interleavings of some input lists. Internally we'll maintain the invariant that each [a] is non-empty; hence we'll have to establish that invariant before we start recursing. In fact, this will be wasted work in the way we intend to call this function, but for good abstraction we might as well handle all inputs correctly, right?
interleavings :: [[a]] -> [[a]]
interleavings = go . filter (not . null) where
go [] = [[]]
go xss = do
(xssl, x:xs, xssr) <- zippers xss
(x:) <$> interleavings ([xs | not (null xs)] ++ xssl ++ xssr)
And now we're basically done. All we have to do is feed in an appropriate starting list.
f :: Int -> [[Int]]
f n = interleavings (replicate n <$> [1..n])
Try it in ghci:
> f 2
[[1,1,2,2],[1,2,2,1],[1,2,1,2],[2,2,1,1],[2,1,1,2],[2,1,2,1]]

Combs on a large set doesn't compute Haskell

I'm writing a combs function in haskell
what it needs to do is, when I provide it with a deck of cards, give me every combination of hands possible from that deck of size x
This is the relevant code
combs :: Int -> [a] -> [[a]]
combs 0 _ = [[ ]]
combs i (x:xs) = (filter (isLength i) y)
where y = subs (x:xs)
combs _ _ = [ ]
isLength :: Int -> [a] -> Bool
isLength i x
| length x == i = True
| otherwise = False
subs :: [a] -> [[a]]
subs [ ] = [[ ]]
subs (x : xs) = map (x:) ys ++ ys
where ys = subs xs
However, when I ask it to compute a combs 5 [1..52], e.g. a hand of 5 out of a full deck, it does not provide a result, and keeps running for a really long time
Does anyone know what the problem is and how to speed up this algorithm?
To extract i items from x:xs you can proceed in two ways:
you keep the x, and extract only i-1 elements from xs
you discard x, and extract all the i elements from xs
Hence, a solution is:
comb :: Int -> [a] -> [[a]]
comb 0 _ = [[]] -- only the empty list has 0 elements
comb _ [] = [] -- can not extract > 0 elements from []
comb i (x:xs) = [ x:ys | ys <- comb (i-1) xs ] -- keep x case
++ comb i xs -- discard x case
By the way, the above code also "proves" a well-known recursive formula for the binomial coefficients. You might already have met this formula if you attended a calculus class.
Letting B(k,n) = length (comb k [1..n]), we have
B(k+1,n+1) == B(k,n) + B(k+1,n)
which is just a direct consequence of the last line of the code above.
Right now it's a bit hard to see what you are trying to do - but I guess the problems you have is that you gonna filter and map a lot.
I think a simple way to get what you need is this:
module Combinations where
import Data.List (delete)
combs :: Eq a => Int -> [a] -> [[a]]
combs 0 _ = [[]]
combs i xs = [ y:ys | y <- xs, ys <- combs (i-1) (delete y xs) ]
which uses delete from Data.List
It should be lazy enough to find you combinations quick - of course all will take a while ;)
λ> take 5 $ combs 5 [1..52]
[[1,2,3,4,5],[1,2,3,4,6],[1,2,3,4,7],[1,2,3,4,8],[1,2,3,4,9]]
how does it work
it's one of those recursive combinatorial algorithm that works by selecting a first card y from all the cards xs, and then recursivley gets the rest of the handysfrom the deck without the selected carddelete a xsand then putting it back togethery:ys` inside the list-monad (here using list-comprehensions).
BTW: ther are 311,875,200 such decks ;)
version without list-comprehensions
here is a version without comprehensions in case your system has issues here:
combs :: Eq a => Int -> [a] -> [[a]]
combs 0 _ = [[]]
combs i xs = do
y <- xs
ys <- combs (i-1) (delete y xs)
return $ y:ys
version that will remove permutations
this one uses Ord to get sort the items in ascending order and in doing so removing duplciates in respect to permutaion - for this to work xs is expected to be pre-sorted!
Note chi's version is working with fewer constraints and might be more preformant too - but I thougt this is nice and readable and goes well with the version before so maybe it's of interest to you.
I know it's not a thing often done in Haskell/FP where you strife for the most general and abstract cases but I come form an environment where most strive for readability and understanding (coding for the programmer not only for the compiler) - so be gentle ;)
combs' :: Ord a => Int -> [a] -> [[a]]
combs' 0 _ = [[]]
combs' i xs = [ y:ys | y <- xs, ys <- combs' (i-1) (filter (> y) xs) ]

Resources