The list is
[2, 3, 4]
and I want exponentiate each result. So, it would be:
(2 ^ 3) ^ 4 = 4096
My solution is
use foldl
set manually the first element of the list as the base case
set manually the base case as the first element of the list
The code is
foldl (^) 2 [1, 3, 4]
The trace is
((2 ^ 1) ^ 3) ^ 4 = 4096
Is there a solution without alter the list?
Yes, in case the list is guaranteed to have a first element, we can use foldl1 :: (a -> a -> a) -> [a] -> a which uses the first element of the list as initial accumulator. So we can use:
foldl1 (^) [2, 3, 4]
This of course produces the same result:
Prelude> foldl1 (^) [2,3,4]
4096
Note that in case you use an empty list the above function will error. So you will need to handle that case - if that is a possibility - by some extra logic.
Related
I have an assignment to make a Haskell function to merge 2 lists together without using the ++ operation. I found the following code online and it works as intended but I need help understanding how and why it works. If someone can take me through a step by step on how this function works, I would greatly appreciate it. I am VERY new to Haskell so assume you are explaining this to a 5 year old lol.
merge :: [a] -> [a] -> [a]
merge [] ys = ys
merge (x:xs) ys = x : (merge xs ys)
A list in Haskell is defined as a linked list, with [] as the empty list, and (:) is the "cons" where the first parameter is the head (the first element), and the second element the tail (so a list with the remaining elements). This thus means that a list like [1,4] is represented as (1 : (4 : [])), or more can canonical (:) 1 ((:) 4 []).
If we now want to merge two lists [1,4] and [2,5] for example we thus call merge with merge (1 : (4 : [])) (2 : (5 : [])). The first rule of merge checks if the first parameter is an empty list, which is not the case, so we continue the second rule. This checks if the first list uses a cons data constructor, which is the case. So it unifies x with the head of the list (here 1), and xs with the rest of the list (here [4]). This thus means that it replaces this with:
merge (1 : (4 : [])) (2 : (5 : [])) -> 1 : merge (4 : []) (2 : (5 : []))
Now in the recursive call, the first clause will be checked again, but (:) 4 [] again does not match with the empty list [], so we check the second clause, and again this matches. So in this call x unifies with 4, and xs with []:
merge (4 : [])) (2 : (5 : [])) -> 4 : merge [] (2 : (5 : []))
the last recursion has the empty list data constructor as first parameter. This thus matches with the pattern in the first clause. We thus return the second list:
merge [] (2 : (5 : [])) -> (2 : (5 : []))
the result is thus a list:
(1 : (4 : (2 : (5 : []))))
or in short:
[1,4,2,5]
A list is either empty, or non-empty. If it's non-empty, then it has a head (the first element) and a tail (the rest of the list, minus that first element). If we can say what merge does when its first argument meets both of those cases, then we will have handled every possible case - because that first list, being a list, is either empty or not.
So suppose first we are merging the empty list with another list. In this case, clearly the result is just that other list - there's nothing to merge. This is the easy case, covered in the first line of the function: merge [] ys = ys.
So we're left with the case where the first list is non empty. As previously stated, that means it has a head and a tail. It should be easy to see that, in merging this list with another, the result is the same as if we were to merge the tail with the other list, then add the head to the front afterwards. That's what the second line of the function says, in the language of pattern matching (in particular using the "cons" constructor (:) for breaking a list into a head and tail): merge (x:xs) ys = x : (merge xs ys).
Once we have those, we can compute merge for any two lists. Not only do these two cases cover all possible ones, but crucially they allow us to "work backwards" to always get an answer - because in the recursive case, we express merge (x:xs) in terms of merge xs, and xs is shorter than (x:xs), so by repeating this process we always eventually get back to the empty list case*
A simple example should demonstrate: merge [1, 2, 3] [4, 5, 6] successively becomes:
1 : (merge [2, 3] [4, 5, 6])
1 : (2 : (merge [3] [4, 5, 6]))
1 : (2 : (3 : (merge [] [4, 5, 6])))
1 : (2 : (3 : [4, 5, 6]))
whic we would more normally write as [1, 2, 3, 4, 5, 6].
*actually, this argument relies on that first list being finite. If it's infinite, the recursion never stops - but this still isn't a problem, as the process still allows us to compute any finite number of elements as we want. In fact the result is simply that first list, for any finite number of elements. But don't worry about this case too much if it doesn't make sense to you yet, infinite data structures don't turn up every day!
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 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.
I have a List a and a Maybe a. I want to append the maybe value if it is Just a but do nothing if it is Nothing.
This is what I am currently using:
aList ++ case maybeValue of
Just value ->
[ value ]
Nothing ->
[]
Is there a better (more idiomatic) way of doing this?
Note that prepending is fine too if there is a cleaner way of doing that instead. The list order does not matter.
From Chad's suggestion that prepending is cheaper:
prependMaybe : List a -> Maybe a -> List a
prependMaybe list maybe =
case maybe of
Just value ->
value :: list
Nothing ->
list
I think you can use Maybe.map List.singleton yourMaybe |> Maybe.withDefault [].
Here you have a complete example:
appendMaybe : List a -> Maybe a -> List a
appendMaybe list maybe =
Maybe.map List.singleton maybe
|> Maybe.withDefault []
|> (++) list
You can try it on Ellie
If you're going for conciseness, you could use Maybe.Extra.unwrap from the elm-community/maybe-extra package:
import Maybe.Extra exposing (unwrap)
consMaybe : List a -> Maybe a -> List a
consMaybe list =
unwrap list (flip (::) list)
appendMaybe : List a -> Maybe a -> List a
appendMaybe list =
unwrap list ((++) list << List.singleton)
If you really want to go crazy, you can create your own infix operators:
infixr 5 ::?
(::?) = flip consMaybe
infixr 5 ++?
(++?) = appendMaybe
This allows the following:
Nothing ::? [2, 3, 4] == [2, 3, 4]
Just 1 ::? [2, 3, 4] == [1, 2, 3, 4]
[2, 3, 4] ++? Nothing == [2, 3, 4]
[2, 3, 4] ++? Just 5 == [2, 3, 4, 5]
Now, whether the infix versions are idiomatic Elm, that's up for debate. If it's something you use a lot, perhaps it's worth it, but most Elm guides urge you to avoid infix operators because they hinder discoverability.
In the end, your original example has the benefit of being readable and probably more readily understandable, since fewer people will be familiar with unwrap. The only suggestion would be that if order truly doesn't matter, then prepending an item to a list is going to be faster than concatenating lists.
All I've been able to find in the documentation that are relevant are ++ and concat.
I thought at first doing the following would give me what I wanted:
[1, 3, 4] ++ [4, 5, 6]
but as you know that just gives [1, 2, 3, 4, 5, 6].
What would I need to do to take in [1, 2, 3] and [4, 5, 6] and get out [[1, 2, 3], [4, 5, 6]]?
As mentioned in comments, a function to take two lists and combine them into a new list can be defined as:
combine :: [a] -> [a] -> [[a]]
combine xs ys = [xs,ys]
This function can't be applied multiple times to create a list of an arbitrary number of lists. Such a function would take a single list and a list of lists and it would add the single list to the list of lists, so it would have type:
push :: [a] -> [[a]] -> [[a]]
This is just (:), though:
push = (:)
As also mentioned in the comments, the value [x,y] can also be written as x : y : [].1 Since both cases can be done with (:), I would guess that what you really want to use is (:), sometimes consing onto [] and sometimes onto a non-empty list.
1 In fact, [x,y] is just syntactic sugar for x:y:[].
think about what the (++) operator does: it concatenates Lists, it does not construct them. This is how it concatenates text Strings into a new String (and not a list of Strings), since Strings are lists of Chars. to construct a new List out of Lists you use (:) like so:
[1,2,3]:[4,5,6]:[]
where youre adding each list as an element of a new list.