To improve my Haskell skills, I'm trying to solve the Advent of Code 2018. As expected, I am already stuck on day 1, specifically on part 2:
--- Part Two ---
You notice that the device repeats the same frequency change list over
and over.
To calibrate the device, you need to find the first frequency it
reaches twice.
For example, using the same list of changes above, the device would
loop as follows:
Current frequency 0, change of +1; resulting frequency 1.
Current frequency 1, change of -2; resulting frequency -1.
Current frequency -1, change of +3; resulting frequency 2.
Current frequency 2, change of +1; resulting frequency 3.
(At this point, the device continues from the start of the list.)
Current frequency 3, change of +1; resulting frequency 4.
Current frequency 4, change of -2; resulting frequency 2, which has
already been seen.
In this example, the first frequency reached twice is 2. Note that
your device might need to repeat its list of frequency changes many
times before a duplicate frequency is found, and that duplicates might
be found while in the middle of processing the list.
Here are other examples:
+1, -1 first reaches 0 twice.
+3, +3, +4, -2, -4 first reaches 10 twice.
-6, +3, +8, +5, -6 first reaches 5 twice.
+7, +7, -2, -7, -4 first reaches 14 twice.
What is the first frequency your device reaches twice?
Basically, I have a very large list vals::[Int] that includes all the frequency changes mentioned above.
Here is the function I wrote for solving this problem:
-- [1] The list of frequency changes
-- [2] The first repeat frequency
-- [1] [2]
part2helper :: [Int] -> Int
part2helper ds = go ds []
where go ds [] = go ds [0]
go (d:ds) [f] = go ds $ (f+d):[f]
go (d:ds) (f:fs) =
if f `elem` fs then f
else go ds $ (d+f):f:fs
I test this function with the values provided in the description in ghci:
*Main> part2helper (cycle [1, -2, 3, 1])
2
*Main> part2helper (cycle [1, -1])
0
*Main> part2helper (cycle [3, 3, 4, -2, -4])
10
*Main> part2helper (cycle [7, 7, -2, -7, -4])
14
*Main>
All result are correct, so I assume my function works correctly. The problem now is, when I compile this into a program that reads the input list from a file, the program never terminates. Here's the code:
module Main where
import System.Environment
main = do
[input] <- getArgs
s <- readFile input
let n = lines $ s
vals = map (read::String->Int) $ fmap (filter (/='+')) n
sol = part2helper (cycle vals)
print sol
-- [1] The list of frequency changes
-- [2] The first repeat frequency
-- [1] [2]
part2helper :: [Int] -> Int
part2helper ds = go ds []
where go ds [] = go ds [0]
go (d:ds) [f] = go ds $ (f+d):[f]
go (d:ds) (f:fs) =
if f `elem` fs then f
else go ds $ (d+f):f:fs
This builds with GHC correctly, but as I said, never terminates and prints no result. What am I missing? The input file can be found here.
You're trying to put everything together in a single function. It's much better if you work in a modular fashion, breaking the problem into smaller ones.
Here's an idea,
generate the sequence of frequencies,
f0, f1, f2...
generate the sequence of cumulative sets of frequencies
{}, {f0}, {f0,f1}, {f0,f1,f2}...
check repeated insertions, i.e.
fi such that fi ∈ {f0..fi-1}
To make things clearer regarding the last point consider,
f0, f1, f2, f3...
{}, {f0}, {f0,f1}, {f0,f1,f2}...`
if f3 were a repetition then f3 ∈ {f0,f1,f2}
This may seem terribly inefficient but because Haskell is lazy, these lists will be generated as needed.
We'll need to import modules to work with sets and maybes,
import Data.Set
import Data.Maybe
Generating the frequencies from the first frequency and a list of frequency changes can be done via scanl (+). The function scanl (+) x xs operates the elements of xs with the operator + , starting at x, generating the cumulative list of sums.
freqs :: Int -> [Int] -> [Int]
freqs = scanl (+)
Now we can generate the list of sets. Here too we use a scanl. In each step we insert a new frequency, and we start with the empty set.
sets :: [Int] -> [Set Int]
sets = scanl (\s x -> insert x s) (empty)
Once we have the frequencies and the sets we are pretty much done.The main function just puts everything together. It combines both lists and finds the first pair (fi , {f0,...,fi-1}) such that fi ∈ {f0,...,fi-1}, and returns the corresponding fi
result :: Int -> [Int] -> Maybe Int
result x xs = let fs = freqs x xs
ss = sets fs
r = find (\(y,s) -> y `elem` s) (zip fs ss)
in fmap fst r
Note find returns a Maybe (Int, Set Int). It may find Nothing or return Just (x,s) for some frequency x that was already in s. We use fmap fst to turn Just (x,s) into Just x.
EDIT
Once you've got things working if you wish to, may optimize a few things, or play around with your style. The following is a more succinct, and possibly a little bit more efficient version.
The list of frequencies and sets can be built together in one go.
freqsets :: Int -> [Int] -> [(Int, Set Int)]
freqsets f0 = scanl (\(f,s) x -> (f+x,insert f s)) (f0,empty)
And so it's ready to use for the result function. Also we can take advantage of Maybe being a monad to make things a bit more readable.
result :: Int -> [Int] -> Maybe Int
result f0 xs = do (f,_) <- find(\(y,s)->y `elem` s) (freqsets f0 xs)
return f
And there you have it, a rather short solution. I like the change in the result function. I like the do notation, as well as not having it calculate the zipping of the two previous lists. I'm not so sure if "fusing" the building of both lists is worth it. It's a bit less readable. Using three functions, one for frequencies, one for sets, and one for zipping, might be best.
Related
I have a Haskell problem and I came up with a solution but I just can't put pen to paper.
Basically I have a function calc that takes in an Int and returns a Float.
calc :: Int -> Int -> Float
In my function g I want to apply this function on an array
g :: [Int] -> [Float]
Since calc takes two Int parameters I want to consume two Ints (
x being the first index of the array and x+1 being second index). This will keep repeating the function on (index of array) [1][2], [2][3], [3][4] etc.
g :: [Int] -> [Float]
g [] = ""
g (x:xs) = map calc x x+1
calc :: Int -> Int -> Float
calc current last = (current - last / last) * 100
I've tried to research online on how to use map and it basically said like this? Any idea why the code doesn't want to compile and if x+1 is even a viable?
Unary map is map but binary map is zipWith. So what's to zip together? The two copies of the same list, shifted by one position one against the other:
calc :: Int -> Int -> Float
g :: [Int] -> [Float]
g xs = zipWith calc xs (drop 1 xs)
This is all. The zipping automatically stops when the shorter sequence runs out.
zipWith foo applies foo to each pair of arguments, each argument coming from the corresponding list, one element after the other. It could be implemented using zip as
zipWith foo xs ys = map (\ (x,y) -> foo x y) $ zip xs ys
= [ foo x y | (x,y) <- zip xs ys ]
but it already does this by itself.
As an illustration, drop 1 [1,2,3] == [2,3] and this means that
zipWith calc [1, 2, 3] (drop 1 [1, 2, 3]) ==
zipWith calc [1, 2, 3]
[2, 3 ] ==
[calc 1
2,
calc 2
3]
You wanted to use indices. Indices are practically never used in Haskell with lists. We instead achieve the same effect by structural jiggling, and then when we advance along the two lists one element at a time, each operation is O(1) because the next element is already at the top of the advanced list. Whereas with the indices we'd have to traverse the same list from the top anew each time, leading to O(k) time per each one (kth) element, i.e. quadratic behavior overall.
update: taking the zipping approach leads to a possibility of code fusion,
g2 xs = zipWith calc xs (drop 1 xs)
= [calc x y | (x,y) <- zip xs (drop 1 xs)]
= [calc x y | (x:y:_) <- tails xs] -- tails ~= iterate (drop 1)
because why build a new structure to house the two consecutive elements when they already appear in a structure ... the original list structure.
Interestingly, Common Lisp has this special kind of map, a map on tails, as part of the language. While the regular map is known there as mapcar, the map on tails is known there as maplist (it's a map on non-empty tails, to be precise).
I think the best a solution is
-- Returns the empty list on empty list due to laziness of zip
g xs = uncurry calc `map` zip xs (tail xs)
-- | |- this is the list of pairs with indeces: [(1,2), (2,3), (3,4) ...]
-- |- this converts a two arguments functions on a function with single 2-tuple argument
EDIT: #Will Ness solution is actually better.
I am new to Haskell, actually I just started, and I would like to get a small hint to the question I am about to ask.
I am currently trying to get the GCD of a given list. For example, having the list [3, 6, 9] it will return 3.
For the moment, I tought of the following aproach, am I going in a good direction?
let getGCD l = map (\x y -> gcd x y) l
Not quite, you don't want map but rather a fold. map will let you transform every element in the list uniformly, so you give it a local transformation a -> b and it gives you a global transformation ([a] -> [b]). This isn't really what you want.
As a quick primer on folds, there's a whole family of them which all let us express computations which we build up by repeatedly applying a function to an initial value, the next element and the list, and then repeating with the result of that application as the new initial value. So foldl' (+) 0 [1, 2, 3, 4] would so something like
foldl' (+) 0 [1, 2, 3, 4] ==>
foldl' (+) 1 [2, 3, 4] ==>
foldl' (+) 3 [3, 4] ==>
foldl' (+) 6 [4] ==>
foldl' (+) 10 [] ==> -- For empty lists we just return the seed given
10
Can you see how to slot your problem into this framework?
More hints
You want to take a list and compute a result which depends on every element of the list, something like
gcdAll :: [Int] -> Int
gcdAll l = foldl' step initial l
is closer to what you want where step takes the current gcd of the list you've processed so far and the next element of the list and returns the next value and initial is the value to start with (and what is returned if l is empty. Since there isn't really a sane value, I'd instead split this into
gcdAll :: [Int] -> Maybe Int
gcdAll [] = Nothing
gcdAll (h : rest) = Just $ foldl' step h rest
so that you correctly signal the possibility of failure, after all, what's the gcd of nothing?
Note that foldl' is imported from Data.List.
You can recursively use gcd on a list (essentially a fold implementation)
gcd' :: (Integral a) => [a] -> a
gcd' [] = 1
gcd' [x] = x
gcd' (x:xs) = gcd x (gcd' xs)
A GCD is a property of a pair of numbers. So, really, you want to look at pairs of numbers drawn from your list. Ultimately you want to end up with a single GCD for the entire list, but as a first step, you want pairs.
There's a widely-known trick for working with consecutive pairs:
f1 list = zipWith f2 list (tail list)
The zipWith function is a bit like map, but works with a pair of lists. In this case, the original list, and the tail of the original list. (Note that this fails if the list is empty.) If you replace f2 with your gcd function, you now have a new list which is the GCD of each consecutive pair of numbers. And this list is one element shorter than the original:
f1 [x, y, z, w] ==> [gcd x y, gcd y z, gcd z w]
So each time you apply f1 to a list, you get a new, shorter list of GCDs. Apply it enough times, and you should end up with just one element...
I just tackled this one and this would be the quickest, simplest
myGCDMultiple = foldr1 gcd
> myGCDMultiple [3,6,9]
3
I'm trying to split a list of Strings in to a List of Lists of Strings
so like in the title [String] -> [[String]]
This has to be done based on length of characters, so that the Lists in the output are no longer than 10. So if input was length 20 this would be broken down in to 2 lists and if length 21 in to 3 lists.
I'm not sure what to use to do this, I don't even know how to brake down a list in to a list of lists never mind based on certain length.
For example if the limit was 5 and the input was:
["abc","cd","abcd","ab"]
The output would be:
[["abc","cd"],["abcd"],["ab"]]
I'd like to be pointed in the right direction and what methods to use, list comprehension? recursion?
Here's an intuitive solution:
import Data.List (foldl')
breakup :: Int -> [[a]] -> [[[a]]]
breakup size = foldl' accumulate [[]]
where accumulate broken l
| length l > size = error "Breakup size too small."
| sum (map length (last broken ++ [l])) <= size
= init broken ++ [last broken ++ [l]]
| otherwise = broken ++ [[l]]
Now, let's go through it line-by-line:
breakup :: Int -> [[a]] -> [[[a]]]
Since you hinted that you may want to generalize the function to accept different size limits, our type signature reflects this. We also generalize beyond [String] (that is, [[Char]]), since our problem is not specific to [[Char]], and could equally apply to any [[a]].
breakup size = foldl' accumulate [[]]
We're using a left fold because we want to transform a list, left-to-right, into our target, which will be a list of sub-lists. Even though we're not concerned with efficiency, we're using Data.List.foldl' instead of Prelude's own foldl because this is standard practice. You can read more about foldl vs. foldl' here.
Our folding function is called accumulate. It will consider a new item and decide whether to place it in the last-created sub-list or to start a new sub-list. To make that judgment, it uses the size we passed in. We start with an initial value of [[]], that is, a list with one empty sub-list.
Now the question is, how should you accumulate your target?
where accumulate broken l
We're using broken to refer to our constructed target so far, and l (for "list") to refer to the next item to process. We'll use guards for the different cases:
| length l > size = error "Breakup size too small."
We need to raise an error if the item surpasses the size limit on its own, since there's no way to place it in a sub-list that satisfies the size limit. (Alternatively, we could build a safe function by wrapping our return value in the Maybe monad, and that's something you should definitely try out on your own.)
| sum (map length (last broken ++ [l])) <= size
= init broken ++ [last broken ++ [l]]
The guard condition is sum (map length (last broken ++ [l])) <= size, and the return value for this guard is init broken ++ [last broken ++ [l]]. Translated into plain English, we might say, "If the item can fit in the last sub-list without going over the size limit, append it there."
| otherwise = broken ++ [[l]]
On the other hand, if there isn't enough "room" in the last sub-list for this item, we start a new sub-list, containing only this item. When the accumulate helper is applied to the next item in the input list, it will decide whether to place that item in this sub-list or start yet another sub-list, following the same logic.
There you have it. Don't forget to import Data.List (foldl') up at the top. As another answer points out, this is not a performant solution if you plan to process 100,000 strings. However, I believe this solution is easier to read and understand. In many cases, readability is the more important optimization.
Thanks for the fun question. Good luck with Haskell, and happy coding!
You can do something like this:
splitByLen :: Int -> [String] -> [[String]]
splitByLen n s = go (zip s $ scanl1 (+) $ map length s) 0
where go [] _ = []
go xs prev = let (lst, rest) = span (\ (x, c) -> c - prev <= n) xs
in (map fst lst) : go rest (snd $ last lst)
And then:
*Main> splitByLen 5 ["abc","cd","abcd","ab"]
[["abc","cd"],["abcd"],["ab"]]
In case there is a string longer than n, this function will fail. Now, what you want to do in those cases depends on your requirements and that was not specified in your question.
[Update]
As requested by #amar47shah, I made a benchmark comparing his solution (breakup) with mine (splitByLen):
import Data.List
import Data.Time.Clock
import Control.DeepSeq
import System.Random
main :: IO ()
main = do
s <- mapM (\ _ -> randomString 10) [1..10000]
test "breakup 10000" $ breakup 10 s
test "splitByLen 10000" $ splitByLen 10 s
putStrLn ""
r <- mapM (\ _ -> randomString 10) [1..100000]
test "breakup 100000" $ breakup 10 r
test "splitByLen 100000" $ splitByLen 10 r
test :: (NFData a) => String -> a -> IO ()
test s a = do time1 <- getCurrentTime
time2 <- a `deepseq` getCurrentTime
putStrLn $ s ++ ": " ++ show (diffUTCTime time2 time1)
randomString :: Int -> IO String
randomString n = do
l <- randomRIO (1,n)
mapM (\ _ -> randomRIO ('a', 'z')) [1..l]
Here are the results:
breakup 10000: 0.904012s
splitByLen 10000: 0.005966s
breakup 100000: 150.945322s
splitByLen 100000: 0.058658s
Here is another approach. It is clear from the problem that the result is a list of lists and we need a running length and an inner list to keep track of how much we have accumulated (We use foldl' with these two as input). We then describe what we want which is basically:
If the length of the current input string itself exceeds the input length, we ignore that string (you may change this if you want a different behavior).
If the new length after we have added the length of the current string is within our input length, we add it to the current result list.
If the new length exceeds the input length, we add the result so far to the output and start a new result list.
chunks len = reverse . map reverse . snd . foldl' f (0, [[]]) where
f (resSoFar#(lenSoFar, (currRes: acc)) curr
| currLength > len = resSoFar -- ignore
| newLen <= len = (newLen, (curr: currRes):acc)
| otherwise = (currLength, [curr]:currRes:acc)
where
newLen = lenSoFar + currLength
currLength = length curr
Every time we add a result to the output list, we add it to the front hence we need reverse . map reverse at the end.
> chunks 5 ["abc","cd","abcd","ab"]
[["abc","cd"],["abcd"],["ab"]]
> chunks 5 ["abc","cd","abcdef","ab"]
[["abc","cd"],["ab"]]
Here is an elementary approach. First, the type String doesn't matter, so we can define our function in terms of a general type a:
breakup :: [a] -> [[a]]
I'll illustrate with a limit of 3 instead of 10. It'll be obvious how to implement it with another limit.
The first pattern will handle lists which are of size >= 3 and the the second pattern handles all of the other cases:
breakup (a1 : a2 : a3 : as) = [a1, a2, a3] : breakup as
breakup as = [ as ]
It is important to have the patterns in this order. That way the second pattern will only be used when the first pattern does not match, i.e. when there are less than 3 elements in the list.
Examples of running this on some inputs:
breakup [1..5] -> [ [1,2,3], [4,5] ]
breakup [1..4] -> [ [1,2,3], [4] ]
breakup [1..2] -> [ [1,2] ]
breakup [1..3] -> [ [1,2,3], [] ]
We see these is an extra [] when we run the function on [1..3]. Fortunately this is easy to fix by inserting another rule before the last one:
breakup [] = []
The complete definition is:
breakup :: [a] -> [[a]]
breakup [] = []
breakup (a1 : a2 : a3 : as) = [a1, a2, a3] : breakup as
breakup as = [ as ]
I'm just learning Haskell and am kind of stuck.
I'd like to compare list elements and measure the difference between them and return the highest one.
Unfortunatly, I do not know how to approach that problem.
For usual, I'd just iterate the list and compare the neighbours but that does not seem to be the way to go in Haskell.
I already tried using map but as I said I do not really know how you can solve that problem.
I'd be thankful for every kind of advice!
Best wishes
Edit: My idea is to first zip all pairs like this pairs a = zip a (tail a). Then I'd like to get all differences (maybe with map?) and then just chose the highest one. I just can't handle the Haskell syntax.
I don't know what you mean by "measure the discrepancy" between list elements, but if you want to calculate the "largest" element in a list, you'd use the built-in maximum function:
maximum :: Ord a => [a] -> a
This function takes a list of values that can be ordered, so all numbers, chars, and strings, among others.
If you want to get the difference between the maximum value and the minimum value, you can use the similar function minimum, then just subtract the two. Sure, there might be a slightly faster solution whereby you only traverse the list once, or you could sort the list then take the first and last elements, but for most cases doing diff xs = maximum xs - minimum xs is plenty fast enough and makes the most sense to someone else.
So what you want to do is compute a difference between successive elements, not calculate the minimum and maximum of each element. You don't need to index directly, but rather use a handy function called zipWith. It takes a binary operation and two lists, and "zips" them together using that binary operation. So something like
zipWith (+) [1, 2, 3] [4, 5, 6] = [1 + 4, 2 + 5, 3 + 6] = [5, 7, 9]
It is rather handy because if one of the lists runs out early, it just stops there. So you could do something like
diff xs = zipWith (-) xs ???
But how do we offset the list by 1? Well, the easy (and safe) way is to use drop 1. You could use tail, but it'll throw an error and crash your program if xs is an empty list, but drop will not
diff xs = zipWith (-) xs $ drop 1 xs
So an example would be
diff [1, 2, 3, 4] = zipWith (-) [1, 2, 3, 4] $ drop 1 [1, 2, 3, 4]
= zipWith (-) [1, 2, 3, 4] [2, 3, 4]
= [1 - 2, 2 - 3, 3 - 4]
= [-1, -1, -1]
This function will return positive and negative values, and we're interested only in the magnitude, so we can then use the abs function:
maxDiff xs = ??? $ map abs $ diff xs
And then using the function I highlighted above:
maxDiff xs = maximum $ map abs $ diff xs
And you're done! If you want to be fancy, you could even write this in point-free notation as
maxDiff = maximum . map abs . diff
Now, this will in fact raise an error on an empty list because maximum [] throws an error, but I'll let you figure out a way to solve that.
As mentioned by bheklilr, maximum is the quick and easy solution.
If you want some of the background though, here's a bit. What we're trying to do is take a list of values and reduce it to a single value. This is known as a fold, and is possible with (among others) the foldl function, which has the signature foldl :: (a -> b -> a) -> a -> [b] -> a.
The (a -> b -> a) section of foldl is a function which takes two values and returns one of the first type. In our case, this should be our comparison function:
myMax :: Ord a => a -> a -> a
myMax x y | x > y = x
| otherwise = y
(note that Ord a is required so that we can compare our values).
So, we can say
-- This doesn't work!
myMaximum :: Ord a => [a] -> a
myMaximum list = foldl myMax _ list
But what is _? It doesn't make sense to have a starting value for this function, so we turn instead to foldl1, which does not require a starting value (instead it takes the first two values from the list). That makes our maximum function
myMaximum :: Ord a => [a] -> a
myMaximum list = foldl1 myMax list
or, in pointfree format,
myMaximum :: Ord a => [a] -> a
myMaximum = foldl1 myMax
If you look at the actual definition of maximum in Data.List, you'll see it uses this same method.
map maps a function over a list. It transforms each thing1 in a list to a thing2.
What you want is to find the biggest difference between two neighbours, which you can't do with map alone. I'll assume you're only looking at numbers for now, because that's just easier.
diffs :: (Num a) => [a] -> [a]
diffs [] = []
diffs [x] = []
diffs (x1:x2:xs) = abs(x1-x2) : (diffs$x2:xs)
mnd :: (Num a, Ord a) => [a] -> a
mnd [] = 0
mnd [x] = 0
mnd xs = maximum$diffs xs
So diffs takes each list item one at a time and gets the absolute difference between it and its neighbour, then puts that at the front of a list it creates at it goes along (the : operator puts an individual element at the front of a list).
mnd is just a wrapper around maximum$diffs xs that stop exceptions being thrown.
Hi i'm having problems summing my hand up since an Ace can be 1 or 11. How can I make a function which takes in a hand, ie [Card] and calculates the total value?
Here is what I have so far:
handValue :: [Card]->[Int]
handValue [] = 0
handValue (x:xs) = sum((val x)++([handValue xs]))
where val is already defined and returns from a card an array of values. eg val ("Ace","Hearts") gives [1,11] val ("Five","Hearts") gives [5]
Any pointers would be appreciated.
edit: after duplodes suggestion I have this:
handValue :: [Card]->[Int]
handValue [] = 0
handValue (x:xs) =
if (val x ==[1,11])
then (map sum (sequence [[1,11], handValue xs]))
else [ sum [(val x)]++([handValue xs])]
Beyond fixing your function you should pay attention to why it didn't work in first place. Firstly, the type you gave is
handValue :: [Card] -> [Int]
but your recursive definition has single values, and not lists, as result types (the 0 literal in the first equation; the use of sum, which is Num a => [a] -> a in the second one).
Now, assuming the type was changed to [Card] -> Int, your definition would be legal, but the results would be weird. Your second equation is:
handValue (x:xs) = sum((val x)++([handValue xs]))
What happens if x is an ace? val x will be [1, 11], and so both values will be concatenated and included in the sum. In effect, your aces now count not as 1 or 11, but 12 points! n.m's solution, which I paraphrase here as
Prelude> map sum . sequence $ [[1,11], [5], [6]]
[12,22]
skirts around the problem by generating lists of values for all possible choices of aces (sequence) and summing all possibilities separately (map sum), resulting in a list of values (as in the signature you had originally given). That, however, does not quite settle the issue, as you will eventually need to decide for one of the possibilities. And now we likely have enough material for a different question, once you get to that point...
Prelude Control.Monad> liftM sum . sequence $ [[1,11], [5], [6]]
[12,22]