I am very new to Haskell. Could someone please explain why defining a list like this returns an null list
ghci> let myList = [10..1]
ghci> myList
[]
However this works correctly.
ghci> let myList = [10, 9..1]
ghci> myList
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Basically, because [10..1] is translated to enumFromTo 10 1 which itself has the semantics to create a list by taking all elements less-than 1 which result from counting upward (with step-size +1) from (including) 10.
Whereas [10, 9..1] is translated to enumFromToThen 10 9 1 which explicitly states the counting step-size as 9-10, i.e. -1 (which is hard-coded to +1 for enumFromTo)
A more accurate specification can be found in the Haskell Report (6.3.4 The Enum Class):
enumFrom :: a -> [a] -- [n..]
enumFromThen :: a -> a -> [a] -- [n,n'..]
enumFromTo :: a -> a -> [a] -- [n..m]
enumFromThenTo :: a -> a -> a -> [a] -- [n,n'..m]
For the types Int and Integer, the enumeration functions have the following meaning:
The sequence enumFrom e1 is the list [e1,e1+1,e1+2,...].
The sequence enumFromThen e1 e2 is the list [e1,e1+i,e1+2i,...], where the increment, i, is e2-e1. The increment may be zero or negative. If the increment is zero, all the list elements are the same.
The sequence enumFromTo e1 e3 is the list [e1,e1+1,e1+2,...e3]. The list is empty if e1 > e3.
The sequence enumFromThenTo e1 e2 e3 is the list [e1,e1+i,e1+2i,...e3], where the increment, i, is e2-e1. If the increment is positive or zero, the list terminates when the next element would be greater than e3; the list is empty if e1 > e3. If the increment is negative, the list terminates when the next element would be less than e3; the list is empty if e1 < e3.
Arithmetic sequence notation is just syntactic sugar for functions from the Enum class.
[a..] = enumFrom a
[a..b] = enumFromTo a b
[a, b..] = enumFromThen a b
[a, b..c] = enumFromThenTo a b c
As for why they weren't defined to automatically reverse, I can only speculate but here are some possible reasons:
If a and b are defined elsewhere, it would be harder to tell at a glance in which direction [a..b] would go.
It has nicer mathematical properties to reason about. You don't have to add special cases for when the sequence would be reversed.
If you want to generate a list from a to b regardless of whether a < b, you can use the following:
[a, a + (signum $ b - a)..b]
For newbies.
To make a list with all the numbers from 20 to 1, you can't just do
[20..1]
you have to specify as such:
[20,19..1]
Related
I'm currently trying to solve the following exercise:
Given a list of Ints, count the number of times, an element is greater than the element that comes after it. The exercise forces me not to use explicit recursions.
Here are some example outputs given function :: [Int] -> Int:
function [1, 2, 3, 4, 5] == 0 -- only increasing numbers
function [5, 4, 3, 2, 1] == 4 -- only decreasing numbers
function [2, 1, 3, 1, 0, 4] == 3
-- 2 > 1
-- 3 > 1
-- 1 > 0
function [1] == 0 -- no successor
function [ ] == 0 -- no numbers at all
I imagined to use in some way foldl but after many attempts and not working idea I had to give up.
How can I count the number of times an element is greater than its successor without using recursion?
First we need to pair up the consecutive elements,
foo :: [Int] -> Int
foo xs = result
where
pairs = zip xs (drop 1 xs)
then we can process each pair
biggers = [ () | (x,y) <- pairs, x > y]
and now we can count them,
result = .......
All the nested names belong to the same, shared, nested scope. result must make use of the value of biggers, and biggers refers to the value of pairs which refers to the value of foo's parameter, xs. Make sure to put these code lines into the same definition, all indented by the same amount as the first one, for pairs, one under the other.
Actually using a left fold is also possible:
foo (h:t) = snd ( foldl' (\ (a, !c) x -> (x, if (a > x) then (c+1) else c))
(h,0) t )
foo [] = 0
I think you'll agree though that this is much less self-apparent than the first definition. Also note that it uses a "bang pattern", !, together with foldl', not foldl, to do the counting as soon as possible as we go along the input list, not delaying it until all the input list is traversed in full as foldl would do, needlessly, harming the overall efficiency.
I'm trying to grapple my head around Haskell and I'm having a hard time pinning down the general procedure/algorithm for this specific task. What I want to do is basically give Haskell a list [1,2,3,5,6,9,16,17,18,19] and have it give me back [1-3, 5, 6, 9, 16-19] so essentially turning three or more consecutive numbers into a range in the style of lowestnumber - highestnumber. What I have issue with it I suppose is the all too common difficulty grappling with with the functional paradigm of Haskell. So I would really appreciate a general algorithm or an insight into how to view this from an "Haskellian" point of view.
Thanks in advance.
If I understand the question correctly, the idea is to break up the input lists in chunks, where a chunk is either a single input element or a range of at least three consecutive elements.
So, let's start by defining a datatype for representing such chunks:
data Chunk a = Single a | Range a a
As you can see, the type is parametric in the type of input elements.
Next, we define a function chunks to actually construct a list of chunks from a list of input elements. For this, we require the ability to compare input elements and to obtain the immediate consecutive for a given input element (that is, its successor). Hence, the type of the function reads
chunks :: (Eq a, Enum a) => [a] -> [Chunk a]
Implementation is relatively straightforward:
chunks = foldr go []
where
go x (Single y : Single z : cs) | y == succ x && z == succ y = Range x z : cs
go x (Range y z : cs) | y == succ x = Range x z : cs
go x cs = Single x : cs
We traverse the list from right to left, generating chunks as we go. We generate a range if an input element precedes its two immediate consecutive elements (the first case of the helper function go) or if it precedes a range that starts with its immediate consecutive (the second case). Otherwise, we generate a single element (the final case).
To arrange for pretty output, we declare applications of the type constructor Chunk to be instances of the class Show (given that the type of input elements is in Show):
instance Show a => Show (Chunk a) where
show (Single x ) = show x
show (Range x y) = show x ++ "-" ++ show y
Returning to the example from the question, we then have:
> chunks [1,2,3,5,6,9,16,17,18,19]
[1-3,5,6,9,16-19]
Unfortunately, things are slightly more complicated if we need to account for bounded element types; such types have a largest element for which succ is undefined:
> chunks [maxBound, 1, 2, 3] :: [Chunk Int]
*** Exception: Prelude.Enum.succ{Int}: tried to take `succ' of maxBound
This suggests that we should abstract from the specific approach for determining whether one elements succeeds another:
chunksBy :: (a -> a -> Bool) -> [a] -> [Chunk a]
chunksBy succeeds = foldr go []
where
go x (Single y : Single z : cs) | y `succeeds` x && z `succeeds` y =
Range x z : cs
go x (Range y z : cs) | y `succeeds` x = Range x z : cs
go x cs = Single x : cs
Now, the version of chunks that was given above, can be expressed in terms of chunksBy simply by writing
chunks :: (Eq a, Enum a) => [a] -> [Chunk a]
chunks = chunksBy (\y x -> y == succ x)
Moreover, we can now also implement a version for bounded input types as well:
chunks' :: (Eq a, Enum a, Bounded a) => [a] -> [Chunk a]
chunks' = chunksBy (\y x -> x /= maxBound && y == succ x)
That merrily gives us:
> chunks' [maxBound, 1, 2, 3] :: [Chunk Int]
[9223372036854775807,1-3]
First, all elements of a list must be of the same type. Your resulting list has two different types. Ranges (for what ever that means) and Ints. We should convert one single digit into a range with lowest and highest been the same.
Been said so, You should define the Range data type and fold your list of Int into a list of Range
data Range = Range {from :: Int , to :: Int}
intsToRange :: [Int] -> [Range]
intsToRange [] = []
intsToRange [x] = [Range x x]
intsToRange (x:y:xs) = ... -- hint: you can use and auxiliar acc which holds the lowest value and keep recursion till find a y - x differece greater than 1.
You can also use fold, etc... to get a very haskelly point of view
Use recursion. Recursion is a leap of faith. It is imagining you've already written your definition and so can ("recursively") call it on a sub-problem of your full problem, and combine the (recursively calculated) sub-result with the left-over part to get the full solution -- easy:
ranges xs = let (leftovers, subproblem) = split xs
subresult = ranges subproblem
result = combine leftovers subresult
in
result
where
split xs = ....
combine as rs = ....
Now, we know the type of rs in combine (i.e. subresult in ranges) -- it is what ranges returns:
ranges :: [a] -> rngs
So, how do we split our input list xs? The type-oriented design philosophy says, follow the type.
xs is a list [a] of as. This type has two cases: [] or x:ys with x :: a and ys :: [a]. So the easiest way to split a list into a smaller list and some leftover part is
split (x:xs) = (x, ys)
split [] = *error* "no way to do this" -- intentionally invalid code
Taking note of the last case, we'll have to tweak the overall design to take that into account. But first things first, what's the rngs type could be? Going by your example data, it's a list of rngs, naturally, rngs ~ [rng].
A rng type though, we have a considerable degree of freedom to make it to be whatever we want. The cases we have to account for are pairs and singletons:
data Rng a = Single a
| Pair a a
.... and now we need to fit the jagged pieces together into one picture.
Combining a number with a range which starts from consecutive number is obvious.
Combining a number with a single number will have two obvious cases, for whether those numbers are consecutive or not.
I think / hope you can proceed from here.
Hi I have been looking for an answer but could not find one. Lets say that we have a list like [1,10,4,5,3] how can I shift 5 to left so that this list becomes [1,10,5,4,3].
I tried to swapElementsAt by finding the index of that element but it looks very insufficient.
swapElementsAt :: Int -> [a] -> [a]
swapElementsAt n list = let (beg, a:b:rest) = splitAt (n-1) list in beg ++ b:a:rest
It works like
λ> swapElementsAt 3 [1,10,4,5,3]
[1,10,5,4,3]
Consider how would you write this function if you were to traverse the input list from left to right looking at a very local vicinity of the beginning of the list (since that's what you can easily pattern-match on).
The most straightforward way would be to pattern-match on the first two elements, and check if the second element matches your pattern. If so, just build a new list by swapping these elements and appending the remainder of the list, otherwise, go recursively over the rest.
In code:
swapElem :: Eq a => a -> [a] -> [a]
swapElem e (x:y:xs) | y == e = y : x : xs
swapElem e (x:xs) = x : swapElem e xs
swapElem _ [] = []
The first pattern only matches when there are at least two elements in the list, and the second element is equal to the desired one. If there are less elements or the second element is not the right one, it will fall through to the second pattern, that matches arbitrary non-empty list and calls swapElem on the remainder of the list. The third pattern is there to provide the base recursion case of an empty input list.
Note this code only changes the first occurrence of the target element:
Prelude> swapElem 5 [1, 10, 4, 5, 3]
[1,10,5,4,3]
Prelude> swapElem 5 [1, 10, 5, 4, 5, 3]
[1,5,10,4,5,3]
How would you change it so that it left-shifts all 5s?
Also, the answer depends on what exactly is your input. The answer by #Scarabyte considers the case where you're given the position of the target element, while this approach instead considers the element that you want to shift left.
I'm trying to understand the following function:
q1 :: [Int] -> Int
q1 [] = 0
q1 [x] = x
q1 (x:_:xs) = max x (q1 xs)
When inputting this: q1 (map abs [-1,-6,-5,7]), it gets me 5. Can someone walk me through why this happens? I understand how map functions, but the pattern matching (x:_xs) is a bit confusing. Thanks!
A list in Haskell is - at least conceptually - a linked list. there are two possibilities:
an empty list []; or
a "cons" (x:xs) where x is the head (first item), and xs the tail (the rest of the list).
Haskell also uses syntactical sugar. For instance [1] is behind the curtains translated to (1:[]), and [1,4,2,5] to (1:(4:(2:(5:[])))).
Why is this important? We first will try to understand the q1 function. If we look at the type, we see that q1 takes as input a list of Ints, and returns an Int. It is defined recursively as:
q1 :: [Int] -> Int
q1 [] = 0
q1 [x] = x
q1 (x:_:xs) = max x (q1 xs)
This means that q1 for an empty list is zero (0); that the q1 for a list with one element x is x. For a list with two or more elements is the maximum of the first item of that list x, and tail of the tail of that list. This is because we pattern match with (x:_:xs) which is short for (x:(_:xs)). The underscore basically means "don't care". So the list should be a cons where the tail is a cons as well, and we are interested in the head of the list x, and the tail of the tail of the list xs.
If we reason about this, we thus find out that q1 returns the maximum of the elements at odd indices (so the first, third, fifth, etc. element). In case the list has an even length, we also calculate the maximum with zero (so in case the all elements at odd indices are negative, the function will return zero, but this only in the case we have a list of even length).
Now if wel call it with q1 (map abs [-1,-6,-5,7]), it thus means that we will call q1 on the result of map abs on [-1, -6, -5, 7]. map abs constructs a list where abs is applied to all elements of the list (although it is applied lazily). So after the map abs [-1, -6, -5, 7], we obtain the list [1, 6, 5, 7]. Now the elements at the odd indices are 1 and 5. So q1 will calculate the maximum of these elements and zero (since the length of the list is four, which is even). And max(0, 1, 5) is 5.
Personally, especially the fact that we also consider zero but only in case the list has an even length, is very "unstable". It can result in bugs that are hard to understand, since it can be the result of a detail of the function. We can for instance calculate the maximum with zero, regardless of the length of the list:
q2 :: (Num a, Ord a) => [a] -> a
q2 [] = 0
q2 [x] = max 0 x
q2 (x:_:xs) = max x (q2 xs)
Or we can decide to not use zero at all, and not define maximum over an empty list, like for instance:
q3 :: Ord a => [a] -> a
q3 [x] = x
q3 [x,_] = x
q3 (x:_:xs) = max x (q3 xs)
I'm a Haskell beginner,
I have a function
func :: Num a => [a] -> [a]
func [] = []
func (x:xs) = x + func xs
Each recursion I want to append the value to a list for my output. This function will sum consecutive indexes in a list so that the input [1, 2, 3, 4] produces [1, 3, 6, 10].
How do I append the value generated each time to my list?
Your problem here isn't how to append, but rather how to calculate the value in the first place. Each item needs to be substituted with a sum of itself with all the items preceding it.
Here is one way to do it:
Prelude> func (x:xs) = x:map (+ x) (func xs); func [] = []
Prelude> func [1, 2, 3, 4]
[1,3,6,10]
How does this work? We're given a list that starts with the element x and has the remaining elements xs. We want to increment every item in xs by x, after recursively applying the algorithm to xs.
This is what x:map (+ x) (func xs) does. It reads as "prepend x to the result of mapping every element in func xs through an increment by x".
E.g. for [1, 2, 3, 4], we want 1 to be added to every member of the result of recursively applying the algorithm to [2, 3, 4], then prepended. For [2, 3, 4] we want 2 to be ... to [3, 4]. And so on, until eventually for [4] we want 4 to be added and prepended to the result of applying the algorithm to [].
This is where our base case (func [] = []) kicks in: the algorithm is defined so that it returns an empty list unchanged. Hence func [4] is [4], func [3, 4] is [3, 7], and you keep incrementing and prepending until you get [1,3,6,10].
I think in this particular case, you could use scanl1 like:
scanl1 (+) [1,2,3,4] -- [1,3,6,10]
When iterating over lists, we often use folds, which is a way of reducing the list to a particular value.
There's also another type of operation, which is a fold that collects all results along the way, and that's called a scan (from the docs):
scanl = scanlGo
where
scanlGo :: (b -> a -> b) -> b -> [a] -> [b]
scanlGo f q ls = q : (case ls of
[] -> []
x:xs -> scanlGo f (f q x) xs)
So the scan takes three arguments: a function that takes two values and returns a value, a starter value, and a list of values.
The scan will then return a list.
Thus, what you need is a function that takes two values and returns something of the same type as the first (it's okay if both are the same). Binary addition would work here: +.
You also need a value to start off with (the b, which is the second argument to our function), and 0 is the identity for integer addition, so we should use that.
Finally, we pass your list to get the result.
Try to figure out how to write you function as a fold and then as a scan and you will discover the answer.