Related
I am writing a sudoku Puzzle in Haskell and I have a [[Maybe Int]] where I need to check which of the [Maybe Int] contains the least Nothing elements. In other words, in the following code I should return 1, which is the position of the list with only two Nothing:
newtype Puzzle = Puzzle [[Maybe Int]]
deriving (Show, Eq)
example :: Puzzle
example = [ [Just 3, Just 6, Nothing,Nothing,Just 7, Just 1, Just 2, Nothing,Nothing]
, [Just 7,Just 5, Just 4, Just 9, Just 4, Nothing, Just 1, Just 8, Just 2]
, [Nothing,Nothing,Just 9, Just 2, Nothing,Just 4, Just 7, Nothing,Nothing]
, [Nothing,Nothing,Nothing,Nothing,Just 1, Just 3, Nothing,Just 2, Just 8]
, [Just 4, Nothing,Nothing,Just 5, Nothing,Just 2, Nothing,Nothing,Just 9]
, [Just 2, Just 7, Nothing,Just 4, Just 6, Nothing,Nothing,Nothing,Nothing]
, [Nothing,Nothing,Just 5, Just 3, Nothing,Just 8, Just 9, Nothing,Nothing]
, [Nothing,Just 8, Just 3, Nothing,Nothing,Nothing,Nothing,Just 6, Nothing]
, [Nothing,Nothing,Just 7, Just 6, Just 9, Nothing,Nothing,Just 4, Just 3]
]
[Edit]
I already came up with a solution that does what I want, but this is very slow and inefficient so I am wondering if there is any way to write this in an algorithmically faster way.
nrOfBlanks :: Puzzle -> [Int]
nrOfBlanks sud = map length [ filter isNothing r | r <- rows sud]
whichBlock :: Puzzle -> Maybe Int
whichBlock sud =
whichBlock sud = let i = nrOfBlanks sud
in head(map (\x -> case x of
0 -> elemIndex (foldl1' min (tail i)) i
_ -> elemIndex (foldl1' min i) i) i)
Any help? Thanks in advance!
So you want to find the (index-of) the minimum element according to some metric – in your case number of Nothing elements, but clearly this is a special case of a more general concept: you have some function a -> Int to be used on the elements of an [a] list. In other words, you need a helper with a signature like either
minIndexAccordingTo :: (a -> Int) -> [a] -> Int
or
minimumAccordingTo :: (a -> Int) -> [a] -> a
Something like that is always a good idea to ask Hoogle about. The first one doesn't give useful results, but the second gives as the first two suggestions
maximumOn :: (Partial, Ord b) => (a -> b) -> [a] -> a
minimumOn :: (Partial, Ord b) => (a -> b) -> [a] -> a
So, minimumOn is almost exactly what you need. You can import it from the extra package, or here's a definition that only uses base:
import Data.List (sortOn)
minimumOn :: Ord b => (a -> b) -> [a] -> a
minimumOn f = head . sortOn f
Note that even though sorting is O (n · log n), this definition works in linear time thanks to lazyness.
Now, to use this to find an index, you first need to pair your elements with an index, change the metric accordingly, and then throw away the original values at the end:
minimumIndexOn :: Ord b => (a -> b) -> [a] -> Int
minimumIndexOn f = fst . minimumOn (f . snd) . zip [0..]
I am having some issues writing a Haskell function. I am trying to get the average of a list of triples of doubles. when I divide by just the ' length xs ' , I get an error that the length is an Int, so I tried using fromIntegeral and its not giving me an error but not giving the right answer. For example if I test,
averages [(2.0,1.0,3.0)] it returns [6.0]
averages :: [(Double, Double, Double)] -> [Double]
averages xs = [ (x+y+z) / fromIntegral (length xs) | (x,y,z) <- xs ]
You are missunderstanding your own type function, the avarage is always over 3, because you have a list of triplets (or tuples of three?):
averages :: [(Double, Double, Double)] -> [Double]
averages xs = [ (x+y+z) / 3 | (x,y,z) <- xs ]
$> averages [(8,6,7), (4,4,10), (1,1,1)]
=> [7.0,6.0,1.0]
Note that length xs will evaluate to 1 when you evaluate averages [(2.0,1.0,3.0)]. The list contains a single element: a tuple. Since you are averaging the elements of a triplet, you can just divide by 3.
Others have explained why you're getting the wrong answers, but I would like to urge you to break up your problem into two pieces.
averageTriple :: (Double, Double, Double) -> Double
averageTriple (x,y,z) = ...
averageTriples :: [(Double, Double, Double)] -> [Double]
averageTriples ts = ... -- use averageTriple here
As I try to learn Haskell just for fun and the experience I have no other possibility than to ask you the "dumb" questions of a total beginner ^^.
I stumbled across the problem how it might be possible to find the sums of lists whithin lists e.g. [[1,3],[4,7],[2,5]] = [4,11,7] and I have found no solution so far. Does anybody have a clue how this might work in Haskell?
Think about function types, it may help.
You have [[Int]] and you want a function [[Int]] -> [Int] to get [Int]
The function you want is map sum :: [[Int]] -> [Int]
The following codes was run in ghci
First you have list of list of ints. Note that in this example you need to guide ghci with [[Int]] to get the type you want instead of the confusing generic [[1,3],[4,7],[2,5]] :: Num t => [[t]]
Prelude> let xs = [[1,3],[4,7],[2,5]] :: [[Int]]
Next, you might already know sum, let make one that specific for [Int] instead of generic sum :: (Foldable t, Num a) => t a -> a, this will make the type easier to read
Prelude> let sumInts = sum :: [Int] -> Int
Next, let test the sumInts on some element of xs = [[1,3],[4,7],[2,5]]
Prelude> :t sumInts [1,3]
sumInts [1,3] :: Int
Prelude> sumInts [1,3]
4
Now you can do sum on an element of a list, to do that to entire list you can use map
Prelude> :t map
map :: (a -> b) -> [a] -> [b]
Let see if you pass sumInts to a map what type you will get?
Prelude> :t map sumInts
map sumInts :: [[Int]] -> [Int]
This should work with xs :: [[Int]] but let check type first to make sure
Prelude> :t map sumInts xs
map sumInts xs :: [Int]
Now do the computation
Prelude> map sumInts xs
[4,11,7]
Since sumInts = sum , this also mean sum would work too
Prelude> :t map sum xs
map sum xs :: [Int]
Prelude> map sum xs
[4,11,7]
Note 1: map sum real type is map sum :: (Foldable t, Num b) => [t b] -> [b]) in the last example it was inferred by type [[Int]] of xs to [[Int]] -> [Int]
You can sum a list with sum and you can apply any function to each element of a list with map so the function you are looking for is:
map sum
when you apply the function:
map sum [[1,3],[4,7],[2,5]]
you get your [4,11,7]. What happens is that map walks over the outer list and keeps applying the function that it gets as its first argument (in this case it is the sum function) to every element. At the same time, map collects the results in an output list. So sum is applied to [1,3] with the result 4 to [4,7] with the result 11 and to [2,5] with the result 7, all of which are placed in a list [4,11,7].
I started studying Haskell few days ago, went through the basics and there's a few things left that I can't make sense of.
First of all,
when I try to add something to the beginning of a list with the ':' operator in a GHCi console, it works only if I try to add single literals, but not lists. (5:[1,2,3,4]) would work but ([1,2]:[3,4,5]) would not. However there's this function:
replicate2 n x
| n <= 0 = []
| otherwise = x:replicate2 (n-1) x
As i understand this how it works recursively, let's call replicate2 2 [1,2]:
it will slip through the first guard and hence:
= [1,2]:replicate (2-1) [1,2]
= [1,2]:[1,2]:replicate (1-1) [1,2]
-- since n is now 0 it's an edge condition and first guard returns [], so recursion ends and we get:
= [1,2]:[1,2]:[]
and the function returns [[1,2],[1,2]]
My question: How does this work? Shouldn't Haskell be mad and spit out errors? It does when I try to do that in GHCi.
Well, let's review some things. the principal (= most general) type of the : operator is this:
(:) :: a -> [a] -> [a]
a is a type variable. What this whole thing means is that every time the operator is actually used, the context of its usage determines what type a will stand for in that particular use. So if you're doing this:
example1 :: [Integer]
example1 = 5 : [1, 2]
...in that context a is Integer, and if you're doing this:
example2 :: [[Integer]]
example2 = [1,2] : [[1,2]]
...then in that context a is [Integer]. So what the type means:
(:) :: a -> [a] -> [a]
...is that the type a of the value you're putting at the head of the list must be the same as the type of the values that go into that list. If it's a list whose elements are Integers then the value must be an Integer as well. And in the example that's confusing you, we have a list of lists of Integers, so the first argument of : in that context is a list of Integer.
Haskell is very precise about this, so we could keep going with other examples illustrating the same principle. Here for example we put a list of lists in front of a list of lists of lists:
example3 :: [[[Integer]]]
example3 = [[1, 2], [3, 4]] : [[[1, 2]]]
-- Value: [[[1, 2], [3, 4]], [[1, 2]]]
So going again to the principal type of ::
(:) :: a -> [a] -> [a]
Another way of looking at it is as a pattern that all of the uses of : must obey: the type of the first argument must have one pair of square brackets fewer than the types of the second argument and the result. Another thing it tells us is that : doesn't care about what type a may be—it could be a simple value like Integer, or it could be some complex thing like [[[[Integer]]]], and this function just can't tell the difference.
My Question: How does this work? I don't understand why because it should not.
You're wrong in that it should not, and you're wrong because you forgot that a might as well mean [a].
Let's look at some type equations:
[] :: [a]
(:) :: a -> [a] -> [a]
[1,2,3] :: [Int]
0 : [1,2,3] :: [Int]
Now with a twist:
[] :: [[a]]
(:) :: [a] -> [[a]] -> [[a]]
[[1,2], [3]] :: [[Int]]
[0] : [[1,2], [3]] :: [[Int]]
A list of lists is still a list, of which an element appended by : is... a list.
What is the most simple solution to do this ?
Define a function for calculating the series of Formula 1 race in function "f1Results". The parameter is a list whose elements are lists based on the result of each Grand Prix. Each such list shall contain the names of the competitors listed by the GP result (the winner is the first of the list). The result of the function has to be a list of names of F1 pilots sorted by number of points in the overall F1 season.
f1Results :: [[String]] -> [String]
Points have to be granted for each position like in the list bellow (again the 25 is for the winner) pointsScoring (eg: 1st place 25 points, 2nd place 18 points, etc.).
pointsScoring :: [Int]
pointsScoring = [25, 18, 15, 12, 10, 8, 6, 4, 2, 1]
You have a constant for what the scoring is
scoring :: [Int]
scoring = [25, 18, 15, 12, 10, 8, 6, 4, 2, 1]
Then you need a way for pairing up a driver with the score they got. Whenever you're pairing two things in Haskell, the canonical choice is to use a tuple. The easiest way to construct a list of tuples from two lists is the zip function:
zip :: [a] -> [b] -> [(a, b)]
And in this case can be used to assign scores for a race:
assignScores :: [String] -> [(String, Int)]
assignScores race = zip race scoring
Now, we need a way to total up the scores for a driver for each race. We want to be able to turn something like
[("Bob", 12), ("Joe", 10), ("Bob", 18), ("Joe", 25)]
into
[("Bob", 30), ("Joe", 35)]
The easiest way would be to make a single list of all the scores for all the races
assignAllScores :: [[String]] -> [(String, Int)]
assignAllScores races = concatMap assignScores races
Then we can use sortBy from Data.List to get all the same names next to each other
sortBy :: (a -> a -> Ordering) -> [a] -> [a]
compare :: Ord a => a -> a -> Ordering
sortByDriver :: [(String, Int)] -> [(String, Int)]
sortByDriver races = sortBy (\(n1, s1) (n2, s2) -> compare n1 n2) races
Then we can use groupBy (also from Data.List) to group them all by name
groupBy :: (a -> a -> Bool) -> [a] -> [[a]]
groupByDriver :: [(String, Int)] -> [[(String, Int)]]
groupByDriver races = groupBy (\(n1, s1) (n2, s2) -> n1 == n2) races
But this gives us a list like
[[("Bob", 12), ("Bob", 18)], [("Joe", 10), ("Joe", 25)]]
We now need a way to convert this into the form
[("Bob", [12, 18]), ("Joe", [10, 25])]
where all the scores are aggregated back into a list, and we don't repeat the names at all. This is left as an exercise.
aggregateScores :: [[(String, Int)]] -> [(String, [Int])]
Then we can finally calculate the sum of these scores
sumScores :: [(String, [Int])] -> [(String, Int)]
sumScores races = map (\(name, scores) -> (name, sum scores)) races
Then finally we can sort by the scores to get everyone in order
sortByScore :: [(String, Int)] -> [(String, Int)]
sortByScore races = sortBy (\(n1, s1) (n2, s2) -> compare s2 s1) races
Notice that I have compare s2 s1 instead of compare s1 s2, this means it will be sorted in descending order instead of ascending order.
The last step is to strip out the scores, now we have our list of drivers in order from winner to loser
removeScores :: [(String, Int)] -> [String]
removeScores races = map fst races
So to combine everything together into one function
f1Results :: [[String]] -> [String]
f1Results races =
removeScores $
sortByScore $
sumScores $
aggregateScores $
groupByDriver $
sortByDriver $
assignAllScores races
There are several tricks that can make this code shorter, namely Data.Function.on, Data.Ord.comparing, and a fun operator from Control.Arrow. Don't turn this in as homework, I just wanted to show an alternative that uses less code.
import Data.List
import Data.Function (on)
import Data.Ord (comparing)
scoring :: [Int]
scoring = [25, 18, 15, 12, 10, 8, 6, 4, 2, 1]
f1Results :: [[String]] -> [String]
f1Results =
map fst . sortBy (on (flip compare) snd) .
map ((head *** sum) . unzip) .
groupBy (on (==) fst) . sortBy (comparing fst) .
concatMap (`zip` scoring)
Or using Data.Map:
import Data.Map (assocs, fromListWith)
import Data.List
import Data.Ord (comparing)
scoring :: [Int]
scoring = [25, 18, 15, 12, 10, 8, 6, 4, 2, 1]
f1Results :: [[String]] -> [String]
f1Results =
reverse . map fst . sortBy (comparing snd) .
assocs . fromListWith (+) .
concatMap (`zip` scoring)
One way could be to use a map where the keys are the drivers' names and the values are the scores. To associate scores with drivers for each sublist in f1results, one could zip the sublist with pointsScoring. A function could take each of the zipped sublists and add the score for each driver encountered in (or newly added to) the map. Then sort the map according to the values.
For example,
import qualified Data.Map as M
import Data.List(sortBy)
pointsScoring :: [Int]
pointsScoring = [25, 18, 15, 12]
f1List :: [[String]]
f1List = [["alex","bart","cecyl","dark"]
,["dark","bart","cecyl","alex"]
,["bart","cecyl","alex","dark"]]
f1Results :: [[String]] -> [String]
f1Results list = map fst . sortBy (\(n1,s1) (n2,s2) -> compare s2 s1) . M.toList
$ foldr f M.empty (concatMap (zip pointsScoring) list)
where f (score,name) results = M.insertWithKey updateMap name score results
updateMap key newValue oldValue = newValue + oldValue
Output:
*Main> f1Results f1List
["bart","alex","dark","cecyl"]