tup :: [String] -> [(Int, Int)] - haskell

I want to create a function which takes in a list ["1","2","3","4"] and returns a list of tuples [(1,2),(3,4)], but im not sure how to code it
every n xs = case drop (n-1) xs of
(y:ys) -> y : every n ys
[] -> []
tup :: [String] -> [(Int, Int)]
tup xs = [((read c),(read i)) | c <- (every 1 xs), i <-(every 2 xs)]
is what ive tried but the output is wrong
output:
*Main> tup ["1", "2", "3", "4"]
[(1,2),(1,4),(2,2),(2,4),(3,2),(3,4),(4,2),(4,4)]

You could use pattern matching:
tup [] = []
tup [_] = []
tup (a:b:other) = (read a, read b):(tup other)
The first two cases deal with the empty list and a list of one element. It doesn't make sense to construct a list of tuples out of these, so the function just returns the empty list. The last case simply extracts the two leading values, puts them into a tuple and prepends it to whatever the recursive call returns.

Related

How to handle the last case?

Define a helper function mergers that given all parts of a word, produces a pair of all possible ways to break up the word.  This recursively. The concat function might help you.   
I can seem to use map and concat to solve this problem. I've solved the first 3 cases which were much easier but cant solve the last one.
mergers :: [String] ->[(String,String)]
mergers [] = []
mergers (x:xs)
| xs ==[] = []
mergers (x:xs:xy)
| xy ==[] = [(x,xs)]
mergers (x:xs:xy:_) ->
The function:
mergers ["co","nt","ro","ls"]
should produce all the possible combination of the given strings like
[("co","ntrols"),("cont","rols"),("contro","ls")] 
 
mergers ["co","nt"]
should give
[("co","nt")]  
mergers ["co"]
should return an empty list
[]
The given function will not suffice. Especially since you need to keep track of the items that have passed. We thus probably should use a helper function that keeps track of the items obtained thus far. These items are then put in a concatenated form in the first tuple.
We thus can work with a helper function, like:
mergers :: [[a]] -> [([a], [a])]
mergers [] = []
mergers (x:xs) = helper [x] xs
where helper left right = …
Now in the helper function, if the right list is empty, than we can stop to produce a list. If on the other hand the right list is not-empty, we can emit a 2-tuple where we concatenate both the left and the right in the tuple, and add the first item of the right list to the left if we recurse.
EDIT: since you managed to solve it, we can here yield the items with:
mergers :: [[a]] -> [([a], [a])]
mergers [] = []
mergers (x:xs) = helper [x] xs
where helper _ [] = []
helper la ra#(r:rs) = (concat la, concat ra) : helper (la ++ [r]) rs
This then yields the expected output:
Prelude> mergers ["co","nt","ro","ls"]
[("co","ntrols"),("cont","rols"),("contro","ls")]
Prelude> mergers ["co","nt"]
[("co","nt")]
Prelude> mergers ["co"]
[]

Haskell filter out circular permutations

You have a list with N elements
You only want to print elements that are not circular permuations of other elements of the same list
To check if two strings are the circular permutations of each other I do this, which works fine :
string1 = "abc"
string2 = "cab"
stringconc = string1 ++ string1
if string2 `isInfixOf` stringconc
then -- it's a circular permuation
else -- it's not
Edit : As one comment pointed that out, this test only work for strings of the same size
Back to the real use case :
checkClean :: [String] -> [String] -> IO String
checkClean [] list = return ""
checkClean (x:xs) list = do
let sequence = cleanInfix x list
if sequence /= "abortmath"
then putStr sequence
else return ()
checkClean xs list
cleanInfix :
cleanInfix :: String -> [String] -> String
cleanInfix seq [] = seq
cleanInfix seq (x:xs) = do
let seqconc = x ++ x
if seq `isInfixOf` seqconc && seq /= x
then "abortmath"
else cleanInfix seq xs
However this just outputs... nothing
With some research I found out that sequence in checkClean is always "abortmath"
Also I'm not quite comfortable with this "flag" abortmath, because if by any chance one element of the list is "abortmath", well..
For example :
if I have a list composed of :
NUUNNFFUF
FFUFNUUNN
I should write
NUUNNFFUF
I guess you call your initial code (question) with something like that:
result = ["NUUNNFFUF", "FFUFNUUNN"]
main = do
checkClean result result
It won't print anything because:
the first call of cleanInfix has the arguments following arguments: "NUUNNFFUF" and ["NUUNNFFUF", "FFUFNUUNN"]
in cleanInfix, since seq == x you have a recursive call with the following arguments: "NUUNNFFUF" and ["FFUFNUUNN"]
now, "NUUNNFFUF" is a real permutation of "FFUFNUUNN": cleanInfix returns "abortmath", and checkClean returns ()
then you have a recursive call of checkClean with following arguments: "FFUFNUUNN" and ["NUUNNFFUF", "FFUFNUUNN"]
again, "FFUFNUUNN" is a real permutation of "NUUNNFFUF": cleanInfix returns "abortmath", and checkClean returns ()
this is the end.
Basically, x is a permutation of y and y is a permutation of x, thus x and y are discarded.
Your answer works, but it is horribly complicated.
I won't try to improve either of your codes, but I will make a general comment: you should (you really should) avoid returning a monad when you don't need to: in the question, checkClean just needs to remove duplicates (or "circular duplicates") from a list. That's totally functional: you have all the information you need. Thus, remove those dos, lets and returns!
Now, let's try to focus on this:
You have a list with N elements You only want to print elements that are not circular permuations of other elements of the same list
Why don't you use your initial knowledge on circular permutations?
isCircPermOf x y = x `isInfixOf` (y ++ y)
Now, you need a function that takes a sequence and a list of sequences, and return only the elements of the second that are not circular permutations of the first :
filterCircDuplicates :: String -> [String] -> [String]
filterCircDuplicates seq [] = []
filterCircDuplicates seq (x:xs) =
if seq `isCircPermOf` x
then removeCircDuplicates seq xs
else x:removeCircDuplicates seq xs
This pattern is well know, and you can use filter to simplify it:
filterCircDuplicates seq l = filter (\x -> !seq `isCircPermOf` x) l
Or better:
filterCircDuplicates seq = filter (not.isCircPermOf seq)
Note the signature: not.isCircPermOf seq :: String -> Boolean. It returns true if the current element is not a circular permutation of seq. (You don't have to add the list argument.)
Final step: you need a function that takes a list and return this list without (circular) duplicates.
removeCircDuplicates :: [String] -> [String]
removeCircDuplicates [] = []
removeCircDuplicates (x:xs) = x:filterCircDuplicates x (removeCircDuplicates xs)
When your list has a head and a tail, you clean the tail, then remove the duplicates of the first element of the tail, and keep this first element.
Again, you have a well known pattern, a fold:
removeCircDuplicates = foldr (\x acc -> x:filterCircDuplicates x acc) []
It removes the duplicates from right to left.
And if you want a one-liner:
Prelude Data.List> foldr (\x -> ((:) x).filter(not.(flip isInfixOf (x++x)))) [] ["abcd", "acbd", "cdab", "abdc", "dcab"]
["abcd","acbd","abdc"]
The wonders you can make with a pen and some paper...
So if anyone is interested here is how I solved it, it's probably badly optimised but at least it works (I'm just trying to learn haskell, so it's good enough for now)
-- cleanInfix function
cleanInfix :: String -> [String] -> [String] -> [String]
cleanInfix sequence [] cleanlist = cleanlist
cleanInfix sequence (x:xs) cleanlist = do
-- this is where I check for the circular permuation
let sequenceconc = x ++ x
if sequence `isInfixOf` sequenceconc
then cleanInfix sequence xs (delete x cleanlist)
else cleanInfix sequence xs cleanlist
-- checkClean Function
checkClean :: [String] -> [String] -> [String] -> [String]
checkClean [] listesend cleanlist = cleanlist
checkClean (x:xs) listesend cleanlist = do
-- The first delete is to avoid checking if an element is the circular permuation of... itself, because it obviously is... in some way
let liste2 = cleanInfix x (delete x listesend) cleanlist
checkClean xs (delete x listesend) liste2
-- Clean function, first second and third are the command line argument don't worry about them
clean first second third = do
-- create of the result list by asking user for input
let printlist = checkClean result result result -- yes, it's the same list, three times
print printlist -- print the list

Gen for a custom data type in Haskell

I was trying to make a truth table for a list of strings.
Say, I have a list ["a","b"] and as an output, I want
[[("a",True),("b",True)],
[("a",True),("b",False)],
[("a",False),("b",True)],
[("a",False),("b",False)]]
Each of those instances in the truth table are a custom data type defined as
data TableRow = [(String,Bool)]
Is there any easier way of doing this? Until now I have been doing this
genRow :: [String] -> [TableRow]
genRow [] = []
genRow (x:xs) = ((makeRow x True) : genRow xs) ++
((makeRow x False) : genRow xs)
Quite obviously, this does not quite give me what I expect. Note that makeRow just takes in a String and a Bool and returns a TableRow.
Is there any cleaner way of doing this? Thanks
The problem with your program is that genRow :: [String] -> [TableRow] generates a list of TableRow elements, and you cannot use the cons (:) constructor on a (String,Bool) and TableRow since TableRow is [[(String,Bool)]].
You can however easily use list comprehension for that:
genRow :: [String] -> [[(String,Bool)]]
genRow [] = [[]]
genRow (x:xs) = [(x,b):ti | b <- [True,False], ti <- ts]
where ts = genRow xs
The first statement should thus generate a list with one element: the empty list [] (not the empty list as result). Furthermore we use list comprehension: we iterate over the two Bools True and False for b and for each such value, we iterate over the possible values as tails ts and prepend the (x,b) to each of the possible tails.
This gives:
*Main> genRow ["A","B","C"]
[[("A",True),("B",True),("C",True)],
[("A",True),("B",True),("C",False)],
[("A",True),("B",False),("C",True)],
[("A",True),("B",False),("C",False)],
[("A",False),("B",True),("C",True)],
[("A",False),("B",True),("C",False)],
[("A",False),("B",False),("C",True)],
[("A",False),("B",False),("C",False)]]
*Main> genRow ["Foo","Bar"]
[[("Foo",True),("Bar",True)],
[("Foo",True),("Bar",False)],
[("Foo",False),("Bar",True)],
[("Foo",False),("Bar",False)]]
(new lines added for readability)

Numeration count inside a recursive function

I want do do something like:
>enumerate ["banana", "potato", "ice"]
[(1, "banana"), (2, "potato"), (3, "ice")]
I wrote:
enumerate :: [String] -> [(Int, String)]
enumerate [] = []
How may I control/manage the int counter ? Is there a way to do that without a support function ?
Update: I know about Zip function. But for matter of study, I want to implement my own zip function.
Update 2: Currently Code
This is what I did so far, using a support function. Considering that:
1) I want to implement my own zip function;
2) I do not want to change the function struct:
enumerate :: [String] -> [(Int, String)]
enumerate :: [String]->[(Int,String)]
enumerate [] = []
enumerate list = aux 1 list
aux :: Int->[String]->[(Int, String)]
aux _ [] = []
aux i (x:xs) = [(i, x)] ++ aux (i+1) xs
Is it possible to improve this function ? As I don't want to add one more last to the function, so I think support function is the only way to go, right ?
Don't be afraid to write a support function, in fact, see it as opportunity: Why the arbitrary starting value 1? Why not have a function
>enumerateFrom 42 ["banana", "potato", "ice"]
[(42, "banana"), (43, "potato"), (44, "ice")]
Once you have that, enumerate is easy.
Edit:
Either give your aux function a real name, IMHO enumerateFrom is good or move it into a where clause if you know that already. And listen to chi, use x : ... instead of [x] ++ ...
There is already a function which does this called zip (zip :: [a] -> [b] -> [(a,b)]). Now for your function you just can pass a list with 1,2,... as first argument and get your result, e.g.
enumerate :: [String] -> [(Int, String)]
enumerate = zip [1..]
EDIT:
If you also want to implement your own zip function, just use:
zip' :: [a] -> [b] -> [(a,b)]
zip' _ [] = []
zip' [] _ = []
zip' (x:xs) (y:ys) = (x,y):zip' xs ys
You take two lists ([a] and [b]) and put each element into a tuple. Edge cases are of cores when one of the lists is empty you return an empty list. Otherwise you use pattern matching to get the first element of the list put them into a tuple and call zip' again with the tail of the list.
As you clarified you wanted to implement your own zip:
zip' [] _ = []
zip' _ [] = []
zip' (x:xs) (y:ys) = (x,y) : zip' xs ys

Folding results in an empty list

I'm trying to make a function that will turn [1..10] into [1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10]. What I have so far is prepend which will add a number of the same element to the start of a list:
-- prepend value num times to the start of list (eg: prepend [] 5 1 = [1,1,1,1,1]
prepend :: [a] -> Int -> a -> [a]
prepend [] _ _ = []
prepend list 0 _ = list
prepend list num value = prepend (value : list) (num - 1) value
To create the final list I'm using foldl like this:
foldl (\acc x -> (prepend acc 2 x)) [] [1..10]
I expected it to go through [1..10], and for each element add 2 of x onto acc, but when I put that into GHCI I just get back []
I'm new to Haskell coming from a C/C++ background
If you have an empty list, and you want to prepend some elements, do you really want to return the empty list? No. So remove the following line:
prepend [] _ _ = []
After all, prepend [] 2 0 should be [0,0] and not []. Other than that, it works fine, but you could write it with concatMap and replicate:
concatMap (replicate 2) [1..10]

Resources