Checking cyclic list of tuples in Haskell - list

I'm fairly new to Haskell and I'm trying to write a function that checks to see if the domino pieces are in a perfect cycle. The dominos are tuples of two items, and all are in one list. The condition is that the snd of a tuple must be equal to the fst of the next one, and also the fst of the first tuple and snd of the last one should be equal.
so for example:
[(2, 2)] -> true
[(5, 2), (2, 3), (3, 5)] -> true
[(5, 1), (2, 3), (3, 5)] -> false
Here's what I have so far (minimal reproducible version). I think the problem with it is that it doesn't check the first and last one with each other but I have no idea how I would go about solving it:
cycle [(x, y)] = x == y
cycle [(x, y), (a, b)] = and (y == a, x == b)
cycle (head:tail) = do
let (headOfTail:restOfTail) = tail
and (snd head == fst headOfTail, cycle (tail))
Thank you in advance!

One way to solve a problem like this is to use the transitive property of dominoes to make a "virtual" domino. For instance, we can start with a pattern match like so:
cycle ((a,b):(c,d):rest) = ...
At this point, if we know that b and c are equal, then we can pretend we have one big domino that starts with a on one side and has d on the other side. If this new domino (a,d) works with the rest of our dominoes, then we should be good.
See if you can fill in the code!

Related

Finding index of an element of a list of tuples with a wildcard

I am trying to find the index of an element in a list of tuples with Haskell, with the use of a wildcard.
I have adapted my types to make it easier to explain. At the moment, my way of thinking is to use elemIndex.
For example,
> elemIndex 2 [1,2,3,4,5]
Just 1
but in my case, I have a list of tuples such as this:
> elemIndex (2, 20) [(1, 10),(2, 20),(3, 30),(4, 40),(5,50)]
Just 1
I want to be able to only supply the first part of the tuple and get the index, such as this:
> elemIndex (2, _) [(1, 10),(2, 20),(3, 30),(4, 40),(5,50)]
Just 1
but the result I am getting is this:
<interactive>:58:15: error:
• Found hole: _ :: Integer
• In the expression: _
In the first argument of ‘elemIndex’, namely ‘(2, _)’
In the expression:
elemIndex (2, _) [(1, 10), (2, 20), (3, 30), (4, 40), ....]
• Relevant bindings include
it :: Maybe Int (bound at <interactive>:58:1)
I am having trouble deciphering the error message and also cannot figure out how to workaround the error.
Any help will be greatly appreciated, thanks!
The _ is not a wildcard, it is a typed hole [haskell-wiki]. Typed holes are often used to find out what type to fill in.
What you can use here is findIndex :: (a -> Bool) -> [a] -> Maybe Int. Here instead of specifing an element to search for, you can use a predicate (a -> Bool), and the function will then return for a given list the first index that satisfies the predicate (wrapped in a Just data constructor), or Nothing if no element can be found.
You thus can implement this as:
Prelude Data.List> findIndex ((2 ==) . fst) [(1, 10),(2, 20),(3, 30),(4, 40),(5,50)]
Just 1

What is the idiomatic way to compare two lists for equality?

I have two lists I need to check whether their elements are equal (not shallow check, for elements I might rely on Kernel.==/2.)
Currently, I have:
[l1 -- l2] ++ [l2 -- l1] == []
It looks a bit overcomplicated and not quite idiomatic to me. Am I missing something? Is there a better way to compare two lists for equality?
The shortest way I can think of is to sort the lists and compare them:
Enum.sort(l1) == Enum.sort(l2)
This will run in O(n log n) time instead of O(n ^ 2) for your Kernel.--/2 based solution.
We can't use a plain Set data structure here since the list can contain duplicates and their counts must be kept track of. We can use a Map which counts the frequency of each element and then to compare them:
iex(1)> l1 = ~w|a a b|a
[:a, :a, :b]
iex(2)> l2 = ~w|a b|a
[:a, :b]
iex(3)> m1 = l1 |> Enum.reduce(%{}, fn x, acc -> Map.update(acc, x, 1, & &1 + 1) end)
%{a: 2, b: 1}
iex(4)> m2 = l2 |> Enum.reduce(%{}, fn x, acc -> Map.update(acc, x, 1, & &1 + 1) end)
%{a: 1, b: 1}
iex(5)> m1 == m2
false
iex(6)> l2 = ~w|a b a|a
[:a, :b, :a]
iex(7)> m2 = l2 |> Enum.reduce(%{}, fn x, acc -> Map.update(acc, x, 1, & &1 + 1) end)
%{a: 2, b: 1}
iex(8)> m1 == m2
true
This is also O(n log n) so you may want to benchmark the two solutions with the kind of data you'll have to see which performs better.
Dogbert's solution is apt, but it is still in Orcish.
In Erlang this would be:
lists:sort(List1) == lists:sort(List2)
A deep comparison looks very nearly the same, but of course must traverse the structures within each list.
One factor to consider is that very often the ordering of a list is its meaning. Strings are a good example, so are player ranks, start positions, game hotkey locations, and last-used-longest-kept cache lists. So do keep in mind the meaning of the comparison: "Do these two lists contain the same number and type of things?" is not the same as "Are these two lists semantically identical?"
Consider comparing anagrams:
lists:sort("AT ERR GET VICE") == lists:sort("IT ERR ETC GAVE")
That works fine as an anagram comparison, but not at all as a semantic one.

Manipulating Lists in Haskell using Higher-Order Functions and Lambda Calculus

I am trying to write a very simple function that takes a list (for example : [1,2,3,1,5]) and returns a list of elements that are directly after a specific element.
What I have reached so far is:
function element list = filter (\x -> element:x) list
My desired output:
function 1 [1,2,3,1,5]
=>   [2,5]
Try this
map snd $ filter ((== x) . fst) $ zip theList (tail theList)
This won't work on an empty list, you will still need extra code to deal with that.
How does this work?
First, note that the values flow from right to left. The ($) operator allows this to happen. So, the first part evaluated is the zip function.
zip theList (tail theList)
For your example above, this would yield
zip [1,2,3,1,5] [2,3,1,5]
equaling
[(1,2), (2, 3), (3, 1), (1,5)]
which is the set of concurrent pairs in the list.
Next, the filter is applied
filter ((== x) . fst) $ ....
In English, what this says is, filter out only the concurrent pairs whose first element equals x. The output is
[(1,2), (1,5)]
Now we have the list of concurrent pairs starting with 1.
Finally, we apply the map
map snd $ ....
This just pulls out the second value of the pair.
map snd [(1,2), (1,5)] = [2,5]
which is the desired value.
Note, my comment above about failing on the empty list.
This is because tail crashes on the empty list
tail [] --error
There are ways to patch this behavior (see the safe package, for instance), but it is mostly bookkeeping at this point, so I left that for you to work out.
Also note that since all of the functions we used are lazy, this approach would work for lists of infinite length as well.
You can do this quite easily with a simple list comprehension, e.g.:
successors xs i = [y | (x,y) <- zip xs (drop 1 xs), x == i]
This will work to your specifications
next x (i:y:ys) -- look at the first two items in the list
| x == i = -- if the first item == x,
y : next x (y:ys) -- take the second, and continue minus the first element
|otherwise = -- not equal,
next x (y:ys) -- so skip that element
next _ [_] = [] -- if there's no second element, then stop
next _ _ = [] -- if the list is empty, stop

Haskell add unique combinations of list to tuple

Say for example that I have a list like this
list = ["AC", "BA"]
I would like to add every unique combination of this list to a tuple so the result is like this:
[("AC", "AC"),("AC","BA"),("BA", "BA")]
where ("BA","AC") is excluded.
My first approach was to use a list comprehension like this:
ya = [(x,y) | x <- list, y <- list]
But I couldn't manage to get it to work, is there anyway to achieve my result by using list comprehensions?
My preferred solution uses a list comprehension
f :: [t] -> [(t, t)]
f list = [ (a,b) | theTail#(a:_) <- tails list , b <- theTail ]
I find this to be quite readable: first you choose (non-deterministically) a suffix theTail, starting with a, and then you choose (non-deterministically) an element b of the suffix. Finally, the pair (a,b) is produced, which clearly ranges over the wanted pairs.
It should also be optimally efficient: every time you demand an element from it, that is produced in constant time.
ThreeFx's answer will work, but it adds the constraint that you elements must be orderable. Instead, you can get away with functions in Prelude and Data.List to implement this more efficiently and more generically:
import Data.List (tails)
permutations2 :: [a] -> [(a, a)]
permutations2 list
= concat
$ zipWith (zip . repeat) list
$ tails list
It doesn't use list comprehensions, but it works without having to perform potentially expensive comparisons and without any constraints on what kind of values you can put through it.
To see how this works, consider that if you had the list [1, 2, 3], you'd have the groups
[(1, 1), (1, 2), (1, 3),
(2, 2), (2, 3),
(3, 3)]
This is equivalent to
[(1, [1, 2, 3]),
(2, [2, 3]),
(3, [3])]
since it doesn't contain any extra or any less information. The transformation from this form to our desired output is to map the function f (x, ys) = map (\y -> (x, y)) ys over each tuple, then concat them together. Now we just need to figure out how to get the second element of those tuples. Quite clearly, we see that all its doing is dropping successive elements off the front of the list. Luckily, this is already implemented for us by the tails function in Data.List. The first element in each of these tuples is just makes up the original list, so we know we can use a zip. Initially, you could implement this with
> concatMap (\(x, ys) -> map (\y -> (x, y)) ys) $ zip list $ tails list
But I personally prefer zips, so I'd turn the inner function into one that doesn't use lambdas more than necessary:
> concatMap (\(x, ys) -> zip (repeat x) ys) $ zip list $ tails list
And since I prefer zipWith f over map (uncurry f) . zip, I'd turn this into
> concat $ zipWith (\x ys -> zip (repeat x) ys) list $ tails list
Now, we can reduce this further:
> concat $ zipWith (\x -> zip (repeat x)) list $ tails list
> concat $ zipWith (zip . repeat) list $ tails list
thanks the eta-reduction and function composition. We could make this entirely pointfree where
> permutations2 = concat . ap (zipWith (zip . repeat)) tails
But I find this pretty hard to read and understand, so I think I'll stick with the previous version.
Just use a list comprehension:
f :: (Ord a) => [a] -> [(a, a)]
f list = [ (a, b) | a <- list, b <- list, a <= b ]
Since Haskell's String is in the Ord typeclass, which means it can be ordered, you first tell Haskell to get all possible combinations and then exclude every combination where b is greater than a which removes all "duplicate" combinations.
Example output:
> f [1,2,3,4]
[(1,1),(1,2),(1,3),(1,4),(2,2),(2,3),(2,4),(3,3),(3,4),(4,4)]

SML: subtract one list from another list

What is the easiest way to subtract one list from another? Do I need to use ListPair to solve this task? Notic that I need to compare ROWS, not single elements. For instance, there are two lists "L1" and "L2":
L1 =
[(1, 2, 3),
(4, 5, 6)]
L2 =
[(1, 2, 3),
(4, 5, 6),
(3, 2, 3]
I need to get "L3" by applying L3 = L2-L1:
L3 =
[(3, 2, 3)]
Thanks.
As I understand the question, you want to remove the elements in L2 which are also in L1, but only once per occurrence.
A simple solution might involve a helper function to tell you if an element was found in L1, along with the rest of L1 with this element removed.
fun remFirst _ [] rest = (false, rev rest)
| remFirst x (y::ys) rest =
if x = y then
(true, rev rest # ys)
else
remFirst x ys (y :: rest)
Now you can iterate through L2, discarding elements each time remFirst returns true, and then proceeding with the rest of the list.
If instead you want to remove the prefix which L2 has in common with L1, things get a bit simpler.
fun remPref [] _ = []
| remPref xs [] = xs
| remPref (x::xs) (y::ys) = if x = y then remPref xs ys else (x::xs)
UPDATE: The question has now been altered.
If the requirement is now to remove elements from L2 that are in L1, filter is useful.
List.filter (fn x => List.all (fn y => x <> y) L1) L2