Haskell list comprehension with tuple input - haskell

Is it possible to somehow use a tuple as input for a list comprehension? Or maybe a tuple comprehension? I expected the following to work, but it does not.
[x * 2 | x <- (4, 16, 32)]
I can not use lists from the very beginning as the given signature of my homework function is
success :: (Int, Int, Int) -> Int -> (Int, Int, Int) -> Bool
But working with lists would be so much simpler as one part of the task requires me to count how many 1s and 20s there are in the tuples.

Control.Lens has overloaded traversal support for homogeneous tuples of all lengths:
import Control.Lens
-- Convert to list:
(3, 4, 5)^..each -- [3, 4, 5]
(1, 2)^..each -- [1, 2]
-- modify elements:
(4, 16, 32)& each %~ \x -> x * 2 -- (8, 32, 64)
(1, 2)& each %~ (+1) -- (2, 3)
-- operator notation for common modifications (see Control.Lens.Operators):
(1, 2, 3)& each +~ 2 -- (3, 4, 5)
(1, 2, 3)& each *~ 2 -- (2, 4, 6)
-- monadic traversals (here each works like `traverse` for the list monad)
each (\x -> [x, x + 1]) (1, 2) -- [(1,2),(1,3),(2,2),(2,3)]
-- `each` is basically an overloaded "kitchen sink" traversal for
-- common containers. It also works on lists, vectors or maps, for example
[(3, 4), (5, 6)]& each . each +~ 1 -- [(4, 5), (6, 7)]

You could just create a function to convert a triple into a list:
tripleToList :: (a, a, a) -> [a]
tripleToList (a, b, c) = [a, b, c]
then you can do
[x * 2 | x <- tripleToList (4, 16, 32)]

Related

Filter list of tuples depending on if second element is found in another list in haskell

Is there a way in haskell to filter out tuples if second element is found in another list ?
I want same as this but in haskell: Filter list of tuples depending on if second element is found in another list
For example:
list of keys
[1, 2, 3]
list of tuples
[('foo', 2), ('bar', 3), ('oof', 2), ('rab', 5)]
result
[('foo', 2), ('bar', 3), ('oof', 2)]
Consider the elem function:
Prelude> keys = [1, 2, 3]
Prelude> a = 5
Prelude> a `elem` keys
False
Prelude> a = 3
Prelude> a `elem` keys
True
If filter can be used to filter a list based on a function:
Prelude> filter even [3, 6, 8, 1]
[6,8]
How can you write a lambda that determines if the second item in the tuple is in your list of keys?
keys = [1, 2, 3]
tuples = [('foo', 2), ('bar', 3), ('oof', 2), ('rab', 5)]
result = filter (\tpl -> ...) tuples

Count all occurences of each element in a list

How do I efficiently count all occurences of each element in a list? I thought of using an associative list or some hash map, but immutability gets in the way and it's not evidently clear how an (hopefully) elegant solution should arise.
The signature could be like this:
countOccurences :: [a] -> [(a, Int)]
Example:
countOccurences [1, 1, 2, 3, 1, 2, 4]
results in
[(1, 3), (2, 2), (3, 1), (4, 1)]
(order is not important though).
group . sort will produce an output list such as
> group . sort $ [1, 1, 2, 3, 1, 2, 4]
[[1,1,1],[2,2],[3],[4]]
Hence,
> map (head &&& length) . group . sort $ [1, 1, 2, 3, 1, 2, 4]
[(1,3),(2,2),(3,1),(4,1)]
So, we obtain
import Data.List (group, sort)
import Control.Arrow ((&&&))
countOccurences :: Ord a => [a] -> [(a, Int)]
countOccurences = map (head &&& length) . group . sort
It should require only O(n log n) time.
Since chi provided a solution using group . sort, here is one that uses Data.Map:
import qualified Data.Map.Strict as M
import Data.Map.Strict (Map)
histogram :: Ord a => [a] -> Map a Int
histogram = M.fromListWith (+) . (`zip` [1,1..])
This also uses O(n log n) time.
I thought of using an associative list or some hash map, but immutability gets in the way
Data.Map is a tree-based associative map, so maybe this representation is for you.
If you'd rather like an [(a, Int)], M.assocs can convert the Data.Map back:
countOccurrences :: Ord a => [a] -> [(a, Int)]
countOccurrences = M.assocs . histogram

count continuous squares from a certain square

First of all, I have a board (10 x 10) and a list of specific coordinates, I'm trying to write a function that gets a certain coordinate and a list of specific coordinates and counts how many squares from that list is connected. e.g. let's say I send coordinate ('C', 5) and list [('C', 5), ('D', 5), ('D', 6), ('A', 4)], the function should return [('C', 5), ('D', 5), ('D', 6)] because all of the coordinates are connected. It would seem easy at object orientated programming but I cant figure a way to do that in functional programming.
something like this?
connected p = map fst . filter ((<=1).snd) . map (liftA2 (,) id (dist p))
where dist (a,x) (b,y) = max (abs (fromEnum a - fromEnum b)) (abs (y-x))
find the elements where max axis distance is less or equal to one, that is the cell itself or immediate neighbors. Perhaps can be written in a shorter way.
> connected ('C',5) [('C', 5), ('D', 5), ('D', 6), ('A', 4)]
should return
[('C',5), ('D',5), ('D',6)]
It's possible to use applicative style to generate the neighborhood then filter with elem. I used pred and succ to handle Enum instances (e.g. Integer, and Char):
filterConn :: (Char,Integer) -> [(Char,Integer)] -> [(Char,Integer)]
filterConn (r,c) = filter (`elem` genNeighborhood)
where
genNeighborhood = (,) <$> [pred r, r, succ r] <*> [pred c, c, succ c]
Furthermore, to obey bounds like a 10x10 board, I would define custom myPred, mySucc functions that only increment or decrement while obeying the bounds (note there will be duplicates when near a bound):
myPred :: (Enum a, Ord a) => a -> a -> a
myPred bound val = if pred val >= bound then pred val else val
mySucc :: (Enum a, Ord a) => a -> a -> a
mySucc bound val = if succ val <= bound then succ val else val
Then just drop in myPred and mySucc to genNeighborhood with their respective bounds like so:
genNeighborhood = (,) <$> [myPred 'A' r, r, mySucc 'J' r] <*> [myPred 1 c, c, mySucc 10 c]
Finally, use length to count how many squares are connected:
countConn s sqs = length $ filterConn s sqs
References: LYAH, Prelude

Indexed lenses for nested containers

How can I use lenses to obtain keys from multiple levels of nesting?
Consider the following types
data Outer = Outer { _outerMap :: Map String Inner }
data Inner = Inner { _innerMap :: Map Char Int }
makeLenses ''Outer
makeLenses ''Inner
and assume the following example value
example :: Outer
example = Outer $ Map.fromList
[ ("A", Inner $ Map.fromList [ ('a', 1), ('b', 2), ('c', 3) ])
, ("B", Inner $ Map.fromList [ ('a', 4), ('b', 6), ('c', 8) ])
, ("C", Inner $ Map.fromList [ ('a', 5), ('b', 7), ('c', 9) ])
]
Using lenses I can flatten example to a [Int] and filter the odd numbers as follows:
>>> example^..outerMap.folded.innerMap.folded.filtered odd
[1,3,5,7,9]
I can annotate the values with the inner key as follows:
>>> example^#..outerMap.folded.innerMap.ifolded.filtered odd
[('a',1),('c',3),('a',5),('b',7),('c',9)]
But how can I use lenses to annotate the values with both the outer and inner keys, to get the following result?
>>> _whatHere example
[(("A",'a'),1),(("A",'c'),3),(("C",'a'),5),(("C",'b'),7),(("C",'c'),9)]
The following attempt still only returns the inner keys:
>>> example^#..outerMap.ifolded.innerMap.ifolded.filtered odd
[('a',1),('c',3),('a',5),('b',7),('c',9)]
And the following attempt doesn't type-check
>>> example^..outerMap.ifolded.withIndex.alongside id (innerMap.ifolded.filtered odd.withIndex)
error:
• No instance for (Applicative
(Control.Lens.Internal.Getter.AlongsideRight
(Const (Data.Monoid.Endo [([Char], (Char, Int))])) [Char]))
An implementation without lenses might look something like this:
nolens :: Outer -> [((String, Char), Int)]
nolens =
filter (odd . snd)
. foldMap (\(k, i) -> (map (first (k, )) . Map.toList . _innerMap) i)
. Map.toList
. _outerMap
Use (<.>). It's just like (.), except it preserves the indices on both the left and the right. (.) itself (and its alias (.>)) preserves only the index of the RHS, unless the RHS is itself index-preserving, in which case the index comes from the LHS. The mnemonic is that the arrows point to the indices you'd like to save.
>>> example^#..outerMap.ifolded<.>innerMap.ifolded.filtered odd
[(("A",'a'),1),(("A",'c'),3),(("C",'a'),5),(("C",'b'),7),(("C",'c'),9)]

Haskell: surprising behavior of "groupBy"

I'm trying to figure out the behavior of the library function groupBy (from Data.List), which purports to group elements of a list by an "equality test" function passed in as the first argument. The type signature suggests that the equality test just needs to have type
(a -> a -> Bool)
However, when I use (<) as the "equality test" in GHCi 6.6, the results are not what I expect:
ghci> groupBy (<) [1, 2, 3, 2, 4, 1, 5, 9]
[[1,2,3,2,4],[1,5,9]]
Instead I'd expect runs of strictly increasing numbers, like this:
[[1,2,3],[2,4],[1,5,9]]
What am I missing?
Have a look at the ghc implementation of groupBy:
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy _ [] = []
groupBy eq (x:xs) = (x:ys) : groupBy eq zs
where (ys,zs) = span (eq x) xs
Now compare these two outputs:
Prelude List> groupBy (<) [1, 2, 3, 2, 4, 1, 5, 9]
[[1,2,3,2,4],[1,5,9]]
Prelude List> groupBy (<) [8, 2, 3, 2, 4, 1, 5, 9]
[[8],[2,3],[2,4],[1,5,9]]
In short, what happens is this: groupBy assumes that the given function (the first argument) tests for equality, and thus assumes that the comparison function is reflexive, transitive and symmetric (see equivalence relation). The problem here is that the less-than relation is not reflexive, nor symmetric.
Edit: The following implementation only assumes transitivity:
groupBy' :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy' _ [] = []
groupBy' _ [x] = [[x]]
groupBy' cmp (x:xs#(x':_)) | cmp x x' = (x:y):ys
| otherwise = [x]:r
where r#(y:ys) = groupBy' cmp xs
The fact that "<" isn't an equality test.
You might expect some behavior because you'd implement it differently, but that isn't what it promises.
An example of why what it outputs is a reasonable answer is if it sweeps through it, doing
[1, 2, 3, 2, 4, 1, 5, 9] ->
[[1,2,3], [2,4], [1,5,9]]
Now has 3 groups of equal elements. So it checks if any of them are in fact the same:
Since it knows all elements in each group is equal, it can just look at the first element in each, 1, 2 and 1.
1 > 2? Yes! So it merges the first two groups.
1 > 1? No! So it leaves the last group be.
And now it's compared all elements for equality.
...only, you didn't pass it the kind of function it expected.
In short, when it wants an equality test, give it an equality test.
The problem is that the reference implementation of groupBy in the Haskell Report compares elements against the first element, so the groups are not strictly increasing (they just have to be all bigger than the first element). What you want instead is a version of groupBy that tests on adjacent elements, like the implementation here.
I'd just like to point out that the groupBy function also requires your list to be sorted before being applied.
For example:
equalityOp :: (a, b1) -> (a, b2) -> Bool
equalityOp x y = fst x == fst y
testData = [(1, 2), (1, 4), (2, 3)]
correctAnswer = groupBy equalityOp testData == [[(1, 2), (1, 4)], [(2, 3)]]
otherTestData = [(1, 2), (2, 3), (1, 4)]
incorrectAnswer = groupBy equalityOp otherTestData == [[(1, 2)], [(2, 3)], [(1, 4)]]
This behaviour comes about because groupBy is using span in its definition. To get reasonable behaviour which doesn't rely on us having the underlying list in any particular order we can define a function:
groupBy' :: (a -> a -> Bool) -> [a] -> [[a]]
groupBy' eq [] = []
groupBy' eq (x:xs) = (x:similarResults) : (groupBy' eq differentResults)
where similarResults = filter (eq x) xs
differentResults = filter (not . eq x) xs

Resources