I was wondering if there is a standard function to combine/merge all elements from a list.
I can't seem to find one.
So for example:
combine["abc","def"] should result in ["abcdef"]
Let me Hoogle that for you...
More generally, the concept of "combining", "merging", is captured by the Monoid class1. It has both a mappend function, for combining two values, and mconcat for flattening a whole list.
1Actually, Semigroup is enough... provided the list isn't empty.
Related
I have to write a Union function using recursion
The ouput has to be the Union (no duplicates) of two lists. My teacher said the implementation has to be recursive and we cannot go through the lists twice but I don't think I can come up with a way of solving the problem without going through the lists twice?
My ideas which would solve the problem (but involve going through lists twice):
- Merge then remove duplicates
- Sorting the lists, then merge
Any hints or help would be appreciated
Edit: Well so I got to combine both lists by doing this:
union1 :: (Eq a) => [a] -> [a] -> [a]
union1 xs [] = xs
union1 [] ys = ys
union1 (x:xs)(y:ys) = x:y:union1(xs)(ys)
Then I thought I could use nub or a similar function to remove the duplicates but I got stuck thinking because then I would be going through the lists twice, right?
What is list union?
I would like to first point out that the requirements your teacher gave you are a bit vague. Moreover, union on multisets (aka sets that can have duplicates, like lists) have two different definitions in mathematics (other source). I am no mathematician, but here is what I was able to glean from various internets. Here is one definition:
λ> [1,2,2,3,3,3] `unionA` [1,2,2,2,3] --also called multiset sum
[1,1,2,2,2,2,2,3,3,3,3]
This is simply (++), if you're not worried about ordering. And here is the other:
λ> [1,2,2,3,3,3] `unionB` [1,2,2,2,3]
[1,2,2,2,3,3,3] --picks out the max number of occurrences from each list
Adding to this confusion, Data.List implements a somewhat quirky third type of union, that treats its left input differently from its right input. Here is approximately the documentation found in comments the source code of union from Data.List:
The union function returns the list union of the two lists. Duplicates, and elements of the first list, are removed from the the second list, but if the first list contains duplicates, so will the result. For example,
λ> "dog" `union` "cow"
"dogcw"
Here, you have 3 possible meanings of "union of lists" to choose from. So unless you had example input and output, I don't know which one your teacher wants, but since the goal is probably for you to learn about recursion, read on...
Removing duplicates
Removing duplicates from unordered lists in Haskell can be done in linear time, but solutions involve either random-access data structures, like Arrays, or something called "productive stable unordered discriminators", like in the discrimination package. I don't think that's what your teacher is looking for, since the first is also common in imperative programming, and the second is too complex for a beginner Haskell course. What your teacher probably meant is that you should traverse each list explicitly only once.
So now for the actual code. Here I will show you how to implement union #3, starting from what you wrote, and still traverse the lists (explicitly) only once. You already have the basic recursion scheme, but you don't need to recurse on both lists, since we opted for option #3, and therefore return the first list unchanged.
Actual code
You'll see in the code below that the first list is used as an "accumulator": while recursing on the second list, we check each element for a duplicate in the first list, and if there isn't a duplicate, we append it to the first list.
union [] r = r
union l [] = l
unionR ls (r:rs)
| r `elem` ls = unionR ls rs --discard head of second list if already seen
--`elem` traverses its second argument,
--but see discussion above.
| otherwise = unionR (r:ls) rs --append head of second list
As a side note, you can make this a bit more readable by using a fold:
union xs = foldl step xs where --xs is our first list; no recursion on it,
--we use it right away as the accumulator.
step els x
| x `elem` els = els
| otherwise = x : els
Given string lists [a, b, c] and [d, e] for example,
return the list [ad, bd, cd, ae, be, ce].
Please don't give me an answer, just a point the the right direction for a new learner.
This problem is tricky because you need to traverse two lists. If you write it as one function there are two recursions to keep track of.
One way to approach it is to start with a simpler problem. Say you have a list of strings l and a string s. Can you write a function that makes a new list with s appended to each of the strings in l?
There is a straightforward solution to this simpler problem using List.map. Or you can write an explicitly recursive function.
After that you have only one remaining recursion to figure out, which may be easier.
Update
Now you have your function you can easily write a function that appends a string to all the elements of the first list of strings. The layout would look like this:
let cross_concat list1 list2 =
let concat_string_to_list1 s = concat_string_to_list list1 s in
...
With this definition, you can use List.map again to get the final results (need to concatenate the resulting lists of strings into one list). Or you can use List.fold_right to build up the result as you go. Or you can write your own recursive function.
If you haven't written too many recursive functions, this would be something to think through.
So I need to define a list predicate: list(.) that returns true if the list is of the form cons(b,cons(d,cons(e,cons(h,nil)))). for the list bdeh.
I need to define the cons(.,.) binary predicate as well.
So far I have :
cons(atom(A),nil):- cons(A,nil).
cons(A,B):- cons(A, cons(B,_)).
list(atom(A)):-cons(A,nil).
list(A):- list(cons(_,A)).
but I don't think that the list(.) predicate is actually traversing through my cons. Can anyone help out in how to traverse the list or to proceed?
I need to define the cons(.,.) binary predicate as well.
Based on your question, cons/2 is not a predicate, it is a functor. A functor has no inherent semantical meaning. A functor is used to structure data in some way that makes sense to the programmer.
Your predicate list/1 needs to verify that the parameter is a list. Two things are lists:
the nil/0 constant; and
a compound term of the functor cons/2 where the second element is a list as well.
So we can define it like:
list(nil).
list(cons(_,X)) :-
list(X).
How does this work? The first clause simply states that nil is a list: if you call list(nil). it will succeed ("return" true). If you do not give it a nil, it will check the second clause and see if you gave it a compound term of cons/2. If that is not the case the clause (and thus the predicate call) will fail. If it is the case, it will unpack the compound term. Prolog is not interested in the first element (that's why we call it _), the second element we name X, and Prolog will perform a recursive call to list/1 with that second element to check if it is a list as well. Therefore it will traverse through the nested cons/2 structures until it finds a nil (or cut off earlier if the second element is not a nil and not a cons/2 compound term).
I want to define predicate which takes a list, adds an element to the list, let's say the number "1", and then returns the list.
I've found out I can add elements to a list using append/3, but I want to use in inside another predicate, thus why I want it to return "my modified list".
My object-oriented mindset tells me to ask the interpreter something like: ?-append(X,5,X). , so that it takes the list X, adds 5 to it, and returns "the new X", but I know that's not how unification works, so my mind is kinda in a glitch.
Can anyone please try to explain how something like this could be achievable?
You are already very close to the solution, so I only rephrase what you are beginning to sense already:
First, you cannot modify a list in pure Prolog.
Instead, you should think in terms of relations between entities. In your case, think in terms of relations between lists.
So, "adding the number 1" to a list is a relation between two lists, which could look like this:
list_with_one(Ls, [1|Ls]).
Note that this works in all directions! You can use it to:
generate answers
test particular cases
"reverse" the direction etc.
So, all you need to do in your case is to think in terms of relations between lists: One without an element, and how this relates to a different list with the element.
Obviously, these two lists will be indicated by different variables and different arguments.
Note in particular that append(X, 5, X) cannot hold: First of all, append/3 is meant to be a relation between lists, and 5 is not a list. Second, assuming you wrote for example append(Xs, [5], Xs), then this would be true if there where a list Xs such that if the element 5 were appended to Xs, the resulting list would again be Xs. Good luck finding such a list... Note also the naming convention to denote lists by letting the variable name end with an s.
It is also falls a bit short to blame this on your "object-oriented mindset", since you can have object oriented programming in Prolog too.
Although lists in Prolog cannot be modified, it is possible to add elements to the end of a list with an unspecified length. In this way, items can be "appended" to a list without creating another list:
:- initialization(main).
append_to_list(List,Item) :-
append_to_list(List,Item,0).
append_to_list(List,Item,Index) :-
% using SWI-Prolog's nth0 predicate
(nth0(Index,List,Check_Item),
var(Check_Item),
nth0(Index,List,Item));
(Next_Index is Index+1,
append_to_list(List,Item,Next_Index)).
main :-
A = [1,2,3|_],
append_to_list(A,4),
append_to_list(A,7),
writeln(A).
In this example, A becomes [1,2,3,4,7|_].
let's say we have a list of elements:
[(a,b); (c,d); (e,f)]
What function would check if element (lets say A, where A=(x,y)) is in the list or not?
Use List.mem to do the search for a match.
let a = (3,4)
List.mem a [(1,2); (3,4); (5,6)]
You can also use List.memq if you want to check if the two items both reference the same entity in memory.
Here's a hint on how to write this yourself. The natural way to to process a list is to initially look at the first element, then check the remainder of the list recursively until you have an empty list. For this problem, you could state the algorithm in English as follows:
If the list is empty then the item is not in the list,
else if the first list element equals the item then it is in,
else it is the answer to (Is the item in the remainder of the list?)
Now you just need to translate this into OCaml code (using a recursive function).
In general, if you can describe what you want to do in terms of smaller or simpler parts of the problem, then writing the recursive code is straightforward (although you have to be careful the base cases are correct). When using a list or tree-structured data the way to decompose the problem is usually obvious.