Haskell List comprehension: show even and double odd elements - list

I've been working on an assignment and I just can't get it to work.
I should write a function that takes a list of numbers and gives back a list that shows even numbers but doubles all odd numbers. (Basically the same list but with doubled odds).
doubleOdd :: [Integer] -> [Integer]
doubleOdd [] = []
doubleOdd a = [x*2 | x <- a, odd x]
My problems are:
I'm only allowed to use +, -, *, /, ==, /=, sum, mod, elem, maximum, odd, even
I don't know how I get different conditions for the same value to work (like if x is even = x and in the same List Comprehension have: if x is odd = x*2)
So far I only got to print the even or the odd numbers, but never both.....
I hope someone can help me.

In case you are looking for a math-trick version:
> take 10 $ [ x + (x `mod` 2) * x | x <- [1..] ]
[2,2,6,4,10,6,14,8,18,10]
(you can do lot's of cheating like this with mod)

In the recursive case treat both possible cases, the case of odds and the case of evens, with the two mutually exclusive tests:
doubleOdd a = [ .... | x <- a, y <- ([x*2 | .... x] ++ [x | .... x]) ]
Since the two tests are mutually exclusive, there will be only one result.
You either must use ++, or the if...then...else. I don't see a way to do this without one or the other.
Or maybe it can be done with some arithmetic trick but then it'd be a math question, not a Haskell question.

Related

Haskell - Defining result as a list and returning null

listX n = xs
if sum[x | x <- [2, 4..n-1], y <- [1..n-1], y `rem` x == 0] == y
then insert y xs
else return ()
Alright, first time trying to work with Haskell, and only having novice Java knowledge has led to some problems.
What I was trying to do, was to define the result of the function listX n as a list called xs.
My idea was that the program would grab every number of from 1 to n, and check if it was equal to the sum of its positive divisors.
Clearly, I have failed horribly and need help, pointers to concepts I haven't understood is extremely appreciated.
Your main problem seems to be that you still think imperative (with the insert) - also () is the value unit - you probably wanted to write [] (the empty list) instead - but still the xs here is totally undefined so you would have to fix this too (and I don't see how to be honest).
perfect numbers
I think I can see a basic idea in there, and I think the best way to fix this is to go full list-comprehension (as you seem to understand them quite well) - here is a version that should work:
listX n = [ x | x <- [1..n], sum [ y | y <- [1..x-1], x `mod` y == 0] == x]
As you can see I changed this a bit - first I check all x from 1 to n if they could be perfect - and I do this by checking by summing up all proper divisors and checking if the sum is equal to x (that's the job of the sum [...] == x part) - in case you don't know this works because you can add guards to list comprehensions (the sum [..] == x filters out all values of x where this is true).
a nicer version
to make this a bit more readable (and separate the concerns) I would suggest writing it that way:
properDivisors :: Integer -> [Integer]
properDivisors n = [ d | d <- [1..n-1], n `mod` d == 0]
isPerfect :: Integer -> Bool
isPerfect n = sum (properDivisors n) == n
perfectNumbers :: [Integer]
perfectNumbers = filter isPerfect [1..]
perfectNumbersUpTo :: Integer -> [Integer]
perfectNumbersUpTo n = takeWhile (<= n) perfectNumbers

List of integers to single integer - Haskell

I seem to be struggling with something that should be extremely simple in Haskell, but I just cannot figure it out and I need some help. I am trying to convert a list of integers ([3,2,1]) and convert it to a single integer (321).
Here is what I have so far:
fromDigits :: [Integer] -> Integer
fromDigits [] = 0;
fromDigits (x:xs) = x : fromDigits (xs)
What am I doing wrong?
You can use the worker wrapper approach to do this:
fromDigits :: [Integer] -> Integer
fromDigits xs = aux xs 0
where aux [] acc = acc
aux (x:xs) acc = aux xs ((acc * 10) + x)
Demo:
λ> fromDigits [3,2,1]
321
Or even you can use the higher order function foldl:
λ> foldl' (\acc x -> (acc * 10) + x) 0 [1,2,3]
123
This is not a conversion. The list [3,2,1] may “look” like the number 321, but it's not a one-to-one relation (as Greg alluded – [32,1] looks like the same number), and most certainly not a canonical one (why would you use base 10? Is this actually hexadecimal?) Hence there is really no reason why this should be particularly simple in Haskell1. This is not JavaScript, fortunately.
Repeat of message... it looks like the number 321, and that's all, it's not related to the number in really any meaningful way. So, if you really need to implement this function of questionable worth (I think you shouldn't), then you might as well do the hack to actually exploit the “looks like” thing. I.e.,
fromDigits = read . filter (not . (`elem`"[,]")) . show
This uses the Show instance of lists, to convert the list [3,2,1] into an actual string "[3,2,1]", then throws away the list-related characters, and reads the concatenated string "321" back, yielding the number 321.
1Apart from the fact that it's generally quite simple to implement pure functions in Haskell...

elm list comprehensions, retrieving the nth element of a list

I was trying to do a simulation of the Rubik's cube in Elm when I noticed Elm doesn't support list comprehensions. In Haskell or even Python I would write something like:
ghci> [2*c | c <- [1,2,3,4]]
[2,4,6,8]
I could not find a way in Elm. The actual list comprehension I had to write was (in Haskell):
ghci> let x = [0,1,3,2]
ghci> let y = [2,3,1,0]
ghci> [y !! fromIntegral c | c <- x]
[2,3,0,1]
where fromIntegral :: (Integral a, Num b) => a -> b turns Integer into Num.
In Elm, I tried to use Arrays:
x = Array.fromList [0,1,3,2]
y = Array.fromList [2,3,1,0]
Array.get (Array.get 2 x) y
And I started getting difficulties with Maybe types:
Expected Type: Maybe number
Actual Type: Int
In fact, I had to look up what they were. Instead of working around the maybe, I just did something with lists:
x = [0,1,3,2]
y = [2,3,1,0]
f n = head ( drop n x)
map f y
I have no idea if that's efficient or correct, but it worked in the cases I tried.
I guess my two main questions are:
does Elm support list comprehensions? ( I guess just use map)
how to get around the maybe types in the Array example?
is it efficient to call head ( drop n x) to get the nth element of a list?
Elm doesn't and will not support list comprehensions: https://github.com/elm-lang/Elm/issues/147
The style guide Evan refers to says 'prefer map, filter, and fold', so.. using `map:
map ((y !!).fromIntegral) x
or
map (\i-> y !! fromIntegral i) x
Commenters point out that (!!) isn't valid Elm (it is valid Haskell). We can define it as either:
(!!) a n = head (drop n a), a total function.
or perhaps
(!!) a n = case (head (drop n a)) of
Just x -> x
Nothing -> crash "(!!) index error"
I don't know much about Elm, so I can't answer to whether it supports list comprehensions (couldn't find anything via Google about it either way), but I can answer your other two questions.
How to get around the Maybe types in the Array example?
The type of Array.get is Int -> Array a -> Maybe a, which means that it returns either Nothing or Just x, where x is the value at the given index. If you want to feed the result of one of these operations into another, in Haskell you could just do
Array.get 2 x >>= \i -> Array.get i y
Or with do notation:
do
i <- Array.get 2 x
Array.get i y
However, from a quick search it seems that Elm may or may not support all monadic types, but hopefully you can still use a case statement to get around this (it's just not very fun)
case Array.get 2 x of
Nothing -> Nothing
Just i -> Array.get i y
In fact, I would recommend writing a function to do this in general for you, it's just a direct clone of >>= for Maybe in Haskell:
mayBind :: Maybe a -> (a -> Maybe b) -> Maybe b
mayBind Nothing _ = Nothing
mayBind (Just x) f = f x
Then you could use it as
Array.get 2 x `mayBind` (\i -> Array.get i y)
Is it efficient to call head (drop n x) to get the nth element of a list?
No, but neither is direct indexing, which is equivalent to head . drop n. For lists, indexing will always be O(n) complexity, meaning it takes n steps to get the nth element from the list. Arrays have a different structure, which lets them index in logarithmic time, which is significantly faster. For small lists (< 100 elements), this doesn't really matter, but once you start getting more than a hundred or a thousand elements, it starts becoming a bottleneck. Lists are great for simple code that doesn't have to be the fastest, as they are generally more convenient. Now, I don't know how exactly this gets translated in Elm, it may be that Elm will convert them into Javascript arrays, which are true arrays and indexable in O(1) time. If Elm uses its own version of Haskell lists after it's been compiled, then you'll still have a slowdown.

Haskell get a filtered List of integers

Scenario:
If there is an array of integers and I want to get array of integers in return that their total should not exceed 10.
I am a beginner in Haskell and tried below. If any one could correct me, would be greatly appreciated.
numbers :: [Int]
numbers = [1,2,3,4,5,6,7,8,9,10, 11, 12]
getUpTo :: [Int] -> Int -> [Int]
getUpTo (x:xs) max =
if max <= 10
then
max = max + x
getUpTo xs max
else
x
Input
getUpTo numbers 0
Output Expected
[1,2,3,4]
BEWARE: This is not a solution to the knapsack problem :)
A very fast solution I came up with is the following one. Of course solving the full knapsack problem would be harder, but if you only need a quick solution this should work:
import Data.List (sort)
getUpTo :: Int -> [Int] -> [Int]
getUpTo max xs = go (sort xs) 0 []
where
go [] sum acc = acc
go (x:xs) sum acc
| x + sum <= max = go xs (x + sum) (x:acc)
| otherwise = acc
By sorting out the array before everything else, I can take items from the top one after another, until the maximum is exceeded; the list built up to that point is then returned.
edit: as a side note, I swapped the order of the first two arguments because this way should be more useful for partial applications.
For educational purposes (and since I felt like explaining something :-), here's a different version, which uses more standard functions. As written it is slower, because it computes a number of sums, and doesn't keep a running total. On the other hand, I think it expresses quite well how to break the problem down.
getUpTo :: [Int] -> [Int]
getUpTo = last . filter (\xs -> sum xs <= 10) . Data.List.inits
I've written the solution as a 'pipeline' of functions; if you apply getUpTo to a list of numbers, Data.List.inits gets applied to the list first, then filter (\xs -> sum xs <= 10) gets applied to the result, and finally last gets applied to the result of that.
So, let's see what each of those three functions do. First off, Data.List.inits returns the initial segments of a list, in increasing order of length. For example, Data.List.inits [2,3,4,5,6] returns [[],[2],[2,3],[2,3,4],[2,3,4,5],[2,3,4,5,6]]. As you can see, this is a list of lists of integers.
Next up, filter (\xs -> sum xs <= 10) goes through these lists of integer in order, keeping them if their sum is less than 10, and discarding them otherwise. The first argument of filter is a predicate which given a list xs returns True if the sum of xs is less than 10. This may be a bit confusing at first, so an example with a simpler predicate is in order, I think. filter even [1,2,3,4,5,6,7] returns [2,4,6] because that are the even values in the original list. In the earlier example, the lists [], [2], [2,3], and [2,3,4] all have a sum less than 10, but [2,3,4,5] and [2,3,4,5,6] don't, so the result of filter (\xs -> sum xs <= 10) . Data.List.inits applied to [2,3,4,5,6] is [[],[2],[2,3],[2,3,4]], again a list of lists of integers.
The last step is the easiest: we just return the last element of the list of lists of integers. This is in principle unsafe, because what should the last element of an empty list be? In our case, we are good to go, since inits always returns the empty list [] first, which has sum 0, which is less than ten - so there's always at least one element in the list of lists we're taking the last element of. We apply last to a list which contains the initial segments of the original list which sum to less than 10, ordered by length. In other words: we return the longest initial segment which sums to less than 10 - which is what you wanted!
If there are negative numbers in your numbers list, this way of doing things can return something you don't expect: getUpTo [10,4,-5,20] returns [10,4,-5] because that is the longest initial segment of [10,4,-5,20] which sums to under 10; even though [10,4] is above 10. If this is not the behaviour you want, and expect [10], then you must replace filter by takeWhile - that essentially stops the filtering as soon as the first element for which the predicate returns False is encountered. E.g. takeWhile [2,4,1,3,6,8,5,7] evaluates to [2,4]. So in our case, using takeWhile stops the moment the sum goes over 10, not trying longer segments.
By writing getUpTo as a composition of functions, it becomes easy to change parts of your algorithm: if you want the longest initial segment that sums exactly to 10, you can use last . filter (\xs -> sum xs == 10) . Data.List.inits. Or if you want to look at the tail segments instead, use head . filter (\xs -> sum xs <= 10) . Data.List.tails; or to take all the possible sublists into account (i.e. an inefficient knapsack solution!): last . filter (\xs -> sum xs <= 10) . Data.List.sortBy (\xs ys -> length xscomparelength ys) . Control.Monad.filterM (const [False,True]) - but I'm not going to explain that here, I've been rambling long enough!
There is an answer with a fast version; however, I thought it might also be instructive to see the minimal change necessary to your code to make it work the way you expect.
numbers :: [Int]
numbers = [1,2,3,4,5,6,7,8,9,10, 11, 12]
getUpTo :: [Int] -> Int -> [Int]
getUpTo (x:xs) max =
if max < 10 -- (<), not (<=)
then
-- return a list that still contains x;
-- can't reassign to max, but can send a
-- different value on to the next
-- iteration of getUpTo
x : getUpTo xs (max + x)
else
[] -- don't want to return any more values here
I am fairly new to Haskell. I just started with it a few hours ago and as such I see in every question a challenge that helps me get out of the imperative way of thinking and a opportunity to practice my recursion thinking :)
I gave some thought to the question and I came up with this, perhaps, naive solution:
upToBound :: (Integral a) => [a] -> a -> [a]
upToBound (x:xs) bound =
let
summation _ [] = []
summation n (m:ms)
| n + m <= bound = m:summation (n + m) ms
| otherwise = []
in
summation 0 (x:xs)
I know there is already a better answer, I just did it for the fun of it.
I have the impression that I changed the signature of the original invocation, because I thought it was pointless to provide an initial zero to the outer function invocation, since I can only assume it can only be zero at first. As such, in my implementation I hid the seed from the caller and provided, instead, the maximum bound, which is more likely to change.
upToBound [1,2,3,4,5,6,7,8,9,0] 10
Which outputs: [1,2,3,4]

Convert list of Integers into one Int (like concat) in haskell

Pretty much what the title says. I have a list of Integers like so: [1,2,3]. I want to change this in to the Integer 123. My first thought was concat but that doesn't work because it's of the wrong type, I've tried various things but usually I just end up returning the same list. Any help greatly appreciated.
Also I have found a way to print the right thing (putStr) except I want the type to be Integer and putStr doesn't do that.
You can use foldl to combine all the elements of a list:
fromDigits = foldl addDigit 0
where addDigit num d = 10*num + d
The addDigit function is called by foldl to add the digits, one after another, starting from the leftmost one.
*Main> fromDigits [1,2,3]
123
Edit:
foldl walks through the list from left to right, adding the elements to accumulate some value.
The second argument of foldl, 0 in this case, is the starting value of the process. In the first step, that starting value is combined with 1, the first element of the list, by calling addDigit 0 1. This results in 10*0+1 = 1. In the next step this 1 is combined with the second element of the list, by addDigit 1 2, giving 10*1+2 = 12. Then this is combined with the third element of the list, by addDigit 12 3, resulting in 10*12+3 = 123.
So pointlessly multiplying by zero is just the first step, in the following steps the multiplication is actually needed to add the new digits "to the end" of the number getting accumulated.
You could concat the string representations of the numbers, and then read them back, like so:
joiner :: [Integer] -> Integer
joiner = read . concatMap show
This worked pretty well for me.
read (concat (map show (x:xs))) :: Int
How function reads:
Step 1 - convert each int in the list to a string
(map show (x:xs))
Step 2 - combine each of those strings together
(concat (step 1))
Step 3 - read the string as the type of int
read (step 2) :: Int
Use read and also intToDigit:
joinInt :: [Int] -> Int
joinInt l = read $ map intToDigit l
Has the advantage (or disadvantage) of puking on multi-digit numbers.
Another idea would be to say: the last digit counts for 1, the next-to last counts for 10, the digit before that counts for 100, etcetera. So to convert a list of digits to a number, you need to reverse it (in order to start at the back), multiply the digits together with the corresponding powers of ten, and add the result together.
To reverse a list, use reverse, to get the powers of ten you can use iterate (*10) 1 (try it in GHCi or Hugs!), to multiply corresponding digits of two lists use zipWith (*) and to add everything together, use sum - it really helps to know a few library functions! Putting the bits together, you get
fromDigits xs = sum (zipWith (*) (reverse xs) (iterate (*10) 1))
Example of evaluation:
fromDigits [1,2,3,4]
==> sum (zipWith (*) (reverse [1,2,3,4]) [1,10,100,1000, ....]
==> sum (zipWith (*) [4,3,2,1] [1,10,100,1000, ....])
==> sum [4 * 1, 3 * 10, 2 * 100, 1 * 1000]
==> 4 + 30 + 200 + 1000
==> 1234
However, this solution is slower than the ones with foldl, due to the call to reverse and since you're building up those powers of ten only to use them directly again. On the plus side, this way of building numbers is closer to the way people usually think (at least I do!), while the foldl-solutions in essence use Horner's rule.
join :: Integral a => [a] -> a
join [x] = x
join (x:xs) = (x * (10 ^ long)) + join(xs)
where long = length(x:xs)
We can define the function called join, that given a list of Integral numbers it can return another Integral number. We are using recursion to separate the head of the given list with the rest of the list and we use pattern matching to define an edge condition so that the recursion can end.
As for how to print the number, instead of
putStr n
just try
putStr (show n)
The reasoning is that putStr can only print strings. So you need to convert the number to a string before passing it in.
You may also want to try the print function from Prelude. This one can print anything that is "showable" (any instance of class Show), not only Strings. But be aware that print n corresponds (roughly) to putStrLn (show n), not putStr (show n).
I'm no expert in Haskell, but this is the easiest way I can think of for a solution to this problem that doesn't involve using any other external functions.
concatDigits :: [Int] -> Int
concatDigits [] = 0
concatDigits xs = concatReversed (reverseDigits xs) 1
reverseDigits :: [Int] -> [Int]
reverseDigits [] = []
reverseDigits (x:xs) = (reverseDigits xs) ++ [x]
concatReversed :: [Int] -> Int -> Int
concatReversed [] d = 0
concatReversed (x:xs) d = (x*d) + concatReversed xs (d*10)
As you can see, I've assumed you're trying to concat a list of digits. If by any chance this is not your case, I'm pretty sure this won't work. :(
In my solution, first of all I've defined a function called reverseDigits, which reverses the original list. For example [1,2,3] to [3,2,1]
After that, I use a concatReversed function which takes a list of digits and number d, which is the result of ten power the first digit on the list position. If the list is empty it returns 0, and if not, it returns the first digit on the list times d, plus the call to concatReversed passing the rest of the list and d times 10.
Hope the code speaks for itself, because I think my poor English explanation wasn't very helpful.
Edit
After a long time, I see my solution is very messy, as it requires reversing the list in order to be able to multiply each digit by 10 power the index of the digit in the list, from right to left. Now knowing tuples, I see that a much better approach is to have a function that receives both the accumulated converted part, and the remainder of the list, so in each invocation in multiplies the accumulated part by 10, and then adds the current digit.
concatDigits :: [Int] -> Int
concatDigits xs = aggregate (xs, 0)
where aggregate :: ([Int], Int) -> Int
aggregate ([], acc) = acc
aggregate (x:xs, acc) = aggregate (xs, (acc * 10 + x))