I have a list with the type `[(Int, Char, Int)]'. E.g:
[(1, 'x', 1), (1, 'y', 2), (2, 'x', 1)]
The first Int is the number of times the Char appears and the second Int is to differentiate the same char from each other. For example, there could be x1 and x2.
I want to join elements of that list that have the same 2nd and 3rd element. In the case of the list above, it would become [(3, 'x', 1), (1, 'y', 2)] (the first and third tuples from the initial list were added together).
I've looked into zipWith and list comprehensions, but none of them seem to work. Is there any other way that I'm not thinking about that might work here?
The two functions you want to use are Data.List.sortBy and Data.List.groupBy.
If we sort by comparing the second and third elements of each tuple, we get the entries in the list sorted by variable and exponent. This is accomplished by passing a lambda which uses pattern macthing to extract and compare just those elements.
import Data.List
lst = [(1, 'x', 1), (1, 'y', 2), (2, 'x', 1)]
lst' = sortBy (\(_, a, b) (_, a', b') -> (a,b) `compare` (a',b')) lst
-- [(1,'x',1), (2,'x',1), (1,'y',2)]
Now we need to group based on the second and third values. groupBy will not work the way you need on an unsorted list, so don't skip that step.
The lambda being passed to groupBy here should look very familiar from the previous example.
lst'' = groupBy (\(_, a, b) (_, a', b') -> a == a' && b == b') lst'
-- [[(1,'x',1), (2,'x',1)], [(1,'y',2)]]
Now summing the first elements of the tuples and incorporating the other information is trivial with list comprehensions.
We get the variable and exponent info from the first element in the list and bind those to x and y respectively, then sum up the first coefficients and build a new tuple.
[let (_,x,y) = lst!!0 in (sum [c | (c,_,_) <- lst], x, y) | lst <- lst'', not (null lst)]
-- [(3,'x',1), (1,'y',2)]
First of all, I would suggest working with more meaningful domain types. A 3-tuple of built-in types could mean a lot of different things. By defining a new type and naming the components, you make everything clearer and prevent mistakes like getting the two Ints mixed up:
type Power = Int
type Coefficient = Int
data Exp var = Exp var Power deriving (Show, Eq, Ord)
data Term var = Term Coefficient (Exp var) deriving Show
What you're doing looks a lot to me like combining terms in polynomials, so I've defined types that make sense in that context. You may prefer different names, or a different structure, if you're actually doing something else.
Now you're looking for a function of type [Term Char] -> [Term Char], which groups together like Exps. Generally Data.Map.fromListWith is a great tool for grouping list items together by a key:
import qualified Data.Map as M
combine :: Ord a => [Term a] -> M.Map (Exp a) Coefficient
combine = M.fromListWith (+) . map toTuple
where toTuple (Term coef exp) = (exp, coef)
Then all that's left is to re-inflate the Map we've extracted to a list again:
simplify :: Ord a => [Term a] -> [Term a]
simplify = map fromTuple . M.assocs . combine
where fromTuple (exp, coef) = Term coef exp
And indeed, we get the grouping you hoped for:
*Main> simplify [Term 1 (Exp 'x' 1), Term 1 (Exp 'y' 2), Term 2 (Exp 'x' 1)]
[Term 3 (Exp 'x' 1),Term 1 (Exp 'y' 2)]
Related
Haskell beginner here.
I have a list of tuples type (a, b) like so: [(1, "One"), (2, "2")], and a single pair (key, value).
I want to create a recursive function that accepts a pair and a list of tuples all type (a, b) and returns the list after replacing all values associated to the passed key with the passed value:
changeTup :: (Eq a) => (a,b) -> [(a,b)] -> [(a,b)]
Example output:
> changeTup (1, "Hello") [(1, "One"), (2, "Two")]
=> [(1, "Hello"), (2, "Two")]
I did some digging and it seems like the best way to do this is with map. I tried this but haven't gotten any good results.
This is my code:
changeTup :: (Eq a) => (a,b) -> [(a,b)] -> [(a,b)]
changeTup (y,z) [] = [(y,z)]
changeTup (y,z) (x:xs) = map replace
where replace (key, value)
| y == key = (key, z)
| otherwise = (key, value)
I'm not sure how to approach increments the list (x:xs) within map. I'm getting an expected type error.
The thing about the map function is that iterating over a list (or another vaguely list-shaped thing) is its entire job. In the code you have, you have a perfectly fine replace function, and you want to apply to the elements of the list (x : xs) - and doing that is as simple as map replace (x : xs)
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
This question is based on to the 11th advent of code task. It basically is a more general version of the river crossing puzzle, you can go up and down floors while carrying one or two items each step. The goal is to bring up all items to the 4th floor.
This is fairly straightforward to solve with an A* search but finding the neighboring states is somewhat annoying.
When solving the puzzle originally I just created masks for all items on the current floor and then used the list monad to generate the combinations - slow and awkward but it works. I figured that there would be an elegant solution using lenses, though.
An easy solution could use a function that returns all options of moving a single item from floor x to floor y. Is there a way to get all combinations of applying a function to a single element using lenses? i.e. f 1 2 [(1, 0), (1, 2)] = [[(2, 0) (1, 2)], [(1, 0), (2, 2)]]
For the sake of reference, this is the best I could come up with so far, slightly simplified:
import Control.Lens
import Data.List (sort)
import Data.Set (fromList, Set)
type GenFloor = Int
type ChipFloor = Int
type State = [(GenFloor, ChipFloor)]
neighborStates :: Int -> State -> Set State
neighborStates currentFloor state = finalize $ createStatesTowards =<< [pred, succ]
where
createStatesTowards direction = traverseOf (traverse . both) (moveTowards direction) state
moveTowards direction i
| i == currentFloor = [direction i, i]
| otherwise = [i]
finalize = fromList . map sort . filter valid
valid = (&&) <$> validCarry <*> validFloors
validCarry = (`elem` [1..2]) . carryCount
carryCount = length . filter (uncurry (/=)) . zip state
validFloors = allOf (traverse . each) (`elem` [1..4])
An easy solution could use a function that returns all options of moving a single item from floor x to floor y. Is there a way to get all combinations of applying a function to a single element using lenses? i.e. f 1 2 [(1, 0), (1, 2)] = [[(2, 0) (1, 2)], [(1, 0), (2, 2)]]
holesOf can do that. Quoting the relevant simplified signature from the documentation:
holesOf :: Traversal' s a -> s -> [Pretext' (->) a s]
Given a traversal, holesOf will generate a list of contexts focused on each element targeted by the traversal. peeks from Control.Comonad.Store can then be used to, from each context, modify the focused target and recreate the surrounding structure:
import Control.Lens
import Control.Comonad.Store
-- allMoves :: Int -> Int -> State -> [State]
allMoves :: (Traversable t, Eq a) => a -> a -> t (a, b) -> [t (a, b)]
allMoves src dst its = peeks (changeFloor src dst) <$> holesOf traverse its
where
-- changeFloor :: Int -> Int -> (Int, Int) -> (Int, Int)
changeFloor src dst = over both (\x -> if x == src then dst else x)
GHCi> allMoves 1 2 [(1,0),(1,2)]
[[(2,0),(1,2)],[(1,0),(2,2)]]
I have a tuple (1, 2, 3) and want to get the third element, however, I keep getting type errors.
Please see the below code:
third (hd : tl) = snd tl
third tpl = head$tail$tail tpl
How can I fix the type errors that are occuring and get the third element correctly?
Tuples aren't lists
In you're code, you're manipulating lists, :, head and tail all work on lists. So
third tpl = head . tail . tail . tail $ tpl
third' (_:_:x:_) = x
Will give you the third element.
a = [1, 2, 3]
>> third a
3
>> third (1, 2, 3)
Error expecting list, but got tuple
Instead you're going to have to use a function of type
thd :: (a, b, c) -> c
This function doesn't exist in the standard libs, it's completely trivial
thd (_, _, a) = a
And that's it :)
You're getting tuples confused with lists:
-- Tuples: Fixed length, mixed types, uses parenthesis
myTuple :: (Int, String)
myTuple = (1, "Hello")
-- Lists: Variable length, single type, uses square brackets
myList :: [Int]
myList = [1, 2, 3, 4]
-- Pattern matching a 3-tuple
isRightTriangle :: (Int, Int, Int) -> Bool
isRightTriangle (a, b, c) = a^2 + b^2 == c^2
-- Pattern matching a 2-tuple
name :: (String, Int) -> String
name (n, a) = n
-- or: name = fst
age :: (String, Int) -> Int
age (n, a) = a
-- or: age = snd
-- Pattern matching a list
thirdElem :: [a] -> a
thirdElem (x1:x2:x3:xs) = x3
thirdElem _ = error "List must have at least 3 elements"
-- or: thirdElem xs = head $ tail $ tail xs
If you haven't already, you should check out Learn You a Haskell For Great Good. It's a great, fun to read introduction to Haskell, starting out with the basic types like strings, tuples, numbers, and lists.
Wondering if I could get some help writing this function. I am trying to create a function that inverts each "pair" in the list.
module Invert where
invert :: [(a,b)] -> [(b,a)]
invert [(a,b)] = [(b,a)]
When I enter invert [(3,1) (4,1) (5,1)]... it is supposed to give me [(1,3) (1,4) (1,5)... But it gives me...
*Invert> [(3,1) (4,1) (5,1)]
<interactive>:2:2:
The function `(3, 1)' is applied to two arguments,
but its type `(t0, t1)' has none
In the expression: (3, 1) (4, 1) (5, 1)
In the expression: [(3, 1) (4, 1) (5, 1)]
In an equation for `it': it = [(3, 1) (4, 1) (5, 1)]
Since lists are recursive data structures, you have to process a list recursively in order to swap all its elements, or use some higher order function that does the processing for you. If you define
invert [(a,b)] = [(b,a)]
it will only convert single-element lists, all other inputs will fail with an error!
Try to think about the input invert gets: It's either an empty list, or a non-empty lists. In the case of a non-empty list, you can swap the first element and convert the rest recursively.
(If you don't want to invert invert yourself, just use
invert = map swap
where swap is from Data.Tuple.)
Best way to solve this: split it into smaller problems, and either find library functions that solve those, or write your own. I always tell beginners that this is a superior exercise than trying to write a function like invert in just one part, because you should be learning the following three things:
How to split a problem into small, reusable pieces.
The standard library functions offered by the language.
How to use recursion to write small, reusable functions like the ones in the standard library.
In this case, we can split the problem into:
Inverting an individual tuple.
Applying a function to all elements of a list, and collecting the list of results.
The second one is just the common map function on lists, which comes with the standard library. You could try writing your own version of it; this sort of thing is always a good exercise for a beginner:
map :: (a -> b) -> [a] -> [b]
map f [] = ...
map f (x:xs) = ...
The first, as Petr points out, is the swap function from Data.Tuple. But we can write our own easily:
swap :: (a, b) -> (b, a)
swap (a, b) = (b, a)
And now, of course:
invert :: [(a, b)] -> [(b, a)]
invert = map swap
So you want to map a function over the list that's of type (a, b) -> (b, a). The function (,) has type b -> a -> (b,a). So if we flip it, we get a -> b -> (b, a). Now if we uncurry that, we get (a, b) -> (b, a):
invert = map (uncurry $ flip (,))
E.g.
> map (uncurry $ flip (,)) [(1, "a"), (2, "b")]
[("a",1),("b",2)]
As an aside, your patten matching doesn't match what you want. The definition
invert [(a,b)] = [(b,a)]
says "match a list with a single tuple in it". If you have a list with multiple tuples, the match will fail. Also, as Josh Lee pointed out, you need commas between tuples in your list.