Sum up distances of a permutation list (Haskell) - haskell

I have a list of Towns and a function, which gives out the distance between two of them. For example:
dist!(Bielefeld,Muenchen) = 598
Now I want to make a function where I can calculate the full length of a random tour between all Towns. For example:
tourlength [a permutation of the 12 Towns] = whole way you have to travel (as Int)
I hope you know what I mean. I'm not sure how to integrate the dist! function into the new one.
My second problem is that I want to calculate which city has the shortest distance to a second one. To solve that, I wanted to use the greedy function below:
greedy a [] = [a]
greedy a X = a : greedy (z X - [z])
z = argmin x : dist a x
tspgreedy X = greedy (s x - [s])
But I don't know how to translate it to haskell...
Thanks for food for thought

In answer to your first question, one way of calculating the total distance of a journey that passes through a series of towns goes like this:
import Data.Complex (Complex, magnitude)
type Town = Complex Double
dist :: Town -> Town -> Int
dist x y = round $ magnitude (x-y)
journeyDistance :: [Town] -> Int
journeyDistance itinerary = sum . zipWith dist itinerary . drop 1 . cycle $ itinerary
(Don't be put off by the use of complex numbers; you can define your towns and the distances between them however you like, say, by a table lookup.) The idea behind this code is to zip the list representing the itinerary with itself -- but offset by one town (hence drop 1) -- calculating distances as we zip. That is, we pair every town with its successor in the itinerary, but the pairing operation is not the usual tuple construction but rather our own distance function (hence zipWith dist). cycle constructs an infinite repetition of the itinerary to ensure there are enough towns to "fully zip" with the original, finite list of towns.
In fact, because the second list in the zip "cycles around", the last town in the first list will be paired with the first town, forming a roundtrip. If you'd rather end your journey in the last town without returning to the first, then you could write the function like this:
journeyDistance itinerary = sum . init . zipWith dist itinerary . drop 1 . cycle $ itinerary
A quick way to solve your second problem might be like this:
import Data.List (minimumBy, tails)
import Data.Ord (comparing)
closestTowns :: [Town] -> (Town, Town)
closestTowns towns = minimumBy (comparing $ uncurry dist) [(x, y) | (x:xs) <- tails towns, y <- xs]

Related

Recursive Haskell function seemingly doesn't terminate

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.

how to do this in haskell ? [x^0,x^1,x^2,x^3 ...]

i want to have a list like this one
[x^0,x^1,x^2,x^3 ...]
is it possible to have such a list
for example
ex : x = 2 [1,2,4,8,16,32 ..]
You can use iterate or unfoldr to double a number many times. This could be more efficient than computing x^n for each n.
Below, I use x=2, but you can use any x.
> take 10 $ iterate (*2) 1
[1,2,4,8,16,32,64,128,256,512]
> take 10 $ unfoldr (\x -> Just (x,2*x)) 1
[1,2,4,8,16,32,64,128,256,512]
Also beware that bounded integer types such as Int will overflow pretty fast in this way.
Yes, it is pretty easy thing to do in haskell.
You create an infinite stream of positive numbers and then map over them with function n ↦ x^n
f :: Num a => a -> [a]
f x = fmap (\n -> x^n) [0..]
> take 10 (f 2)
[1,2,4,8,16,32,64,128,256,512]
In Haskell, the list is linear no matter the progression. By linear, I mean non-recursive. The elements in the list are not dependent on one or more previous elements or an initial element.
In Haskell such lists are used very much. In Haskell there are two primary facilities for producing such lists. The first is map and it is effective without any filtering or recursion.
f b n = map (b^) [0..n]
The second is the list comprehension
f b n = [b^x|x<-[0..n]]
In both it is simple to set the limit or number of elements in the result. These could both be made into infinite lists if desired by excluding the n in both the left and right side of the equations.

How can this Haskell combination algorithm be improved?

How can the solution, presented below, to the following problem be improved? Can it be more efficient in time and space? Is there a space leak?
Problem:
Given an input list of Astronauts, produce a list of pairs of Astronauts such that the pairs do not have two Astronauts from the same country. Assume the input has a list of Astronauts with unique identifiers.
data Astronaut = Astronaut { identifier :: Int, country :: String } deriving (Eq)
astronautPairs :: [Astronaut] -> [(Astronaut, Astronaut)]
astronautPairs xs = foldl accumulatePairs [] [(a, b) | a <- xs, b <- xs, country a /= country b]
where
accumulatePairs pairs pair = if hasPair pair pairs then pairs else pair:pairs
hasPair pair#(a,b) ((c,d):xs) = a == d && b == c || hasPair pair xs
hasPair _ [] = False
Instead of eliminating the flipped pairs why not avoid generating them in the first place. It is we that produce them, yes?
import Data.List (tails)
astronautPairs :: [Astronaut] -> [(Astronaut, Astronaut)]
astronautPairs xs = [ (y,z) | (y:ys) <- tails xs, z <- .... , country y /= country .... ]
This assumes that the input list of astronauts has no duplicates.
Thus, we avoid duplicates by a triangular generation.
(I leave a part of code out, for you to complete).
Let's step back from implementation details and think about what you're trying to accomplish:
produce a list of pairs of Astronauts such that the pairs do not have two Astronauts from the same country
You seem to be allowed to assume that each astronaut appears only once in the list.
One efficient way to approach this problem is to start by partitioning your list by country. A natural way to do this is to build a HashMap String [Int] that holds a list of all the astronauts from each country.
import qualified Data.HashMap.Strict as HMS
import Data.HashMap.Strict (HashMap)
divideAstronauts :: [Astronaut] -> HashMap String [Int]
divideAstronauts = foldl' go mempty where
go hm (Astronaut ident cntry) = HMS.insertWith (++) cntry [ident] hm
Now you can divide up the rest of the program into two steps:
Choose all pairs of countries.
For every pair of countries, choose all pairs of astronauts such that each comes from one of those countries.

Haskell: min distance between neighbor numbers on a list

I'm trying to define a functino that finds the minimum distance between to neighbor numbers on a list
something like this:
minNeighborsDistance [2,3,6,2,0,1,9,8] => 1
My code looks like this:
minNeighborsDistance [] = []
minNeighborsDistance (x:xs) = minimum[minNeighborsDistance xs ++ [subtract x (head xs)]]
Although this seems to run, once I enter a list I receive an Exception error.
I'm new to Haskell I would appreciate any help in this matter.
If you pass a singleton list to minNeighborsDistance then
It'll fail to match [] in the first line, then
it'll successfully match (x:xs) assigning the single value to x and the empty like to xs, then
it'll throw an error when you try to access the head of an empty list.
Further, since you call minNeighborsDistance recursively then you'll always eventually call it on a singleton list excepting when you pass it an empty list.
Here's what I came up with:
minDistance l = minimum . map abs . zipWith (-) l $ tail l
Try this:
minDistance list = minimum (distance list)
where
distance list = map abs $ zipWith (-) list (tail list)
distance calculates the absolute value of the list being subtracted with itself shifted by 1 position:
[2,3,6,2,0,1,9,8] -- the 8 is skipped but it does not make a difference
- [3,6,2,0,1,9,8]
= [1,3,4,2,1,8,1]
minDistance now just gets the smallest element of the resulting list.
Your question is a bit unclear (a type signature would really help here), but if you're wanting to calculate the difference between adjacent elements of the list, then find the minimum of those numbers, I would say the most clear way is to use some extra pattern matching:
-- Is this type you want the function to have?
minNeighborsDistance :: [Int] -> Int
minNeighborsDistance list = minimum $ go list
where
go (x:y:rest) = (x - y) : go (y:rest)
go anythingElse = [] -- Or just go _ = []
However, this won't quite give you the answer you want, because the actual minimum for your example list would be -4 when you go from 6 to 2. But this is an easy fix, just apply abs:
minNeighborsDistance :: [Int] -> Int
minNeighborsDistance list = minimum $ go list
where
go (x:y:rest) = abs (x - y) : go (y:rest)
go anythingElse = []
I've used a helper function to calculate the differences from element to element, then the top-level definition calls minimum on that result to get the final answer.
There is an easier way, though, if you exploit a few functions in Prelude, namely zipWith, map, and drop:
minNeighborsDistance :: [Int] -> Int
minNeighborsDistance list
= minimum -- Calculates the minimum of all the distances
$ (maxBound:) -- Ensures we have at least 1 number to pass to
-- minimum by consing the maximum possible Int
$ map abs -- Ensure all differences are non-negative
-- Compute the difference between each element. I use "drop 1"
-- instead of tail because it won't error on an empty list
$ zipWith (-) list (drop 1 list)
So combined into one line without comments:
minNeighborsDistance list = minimum $ (maxBound:) $ map abs $ zipWith (-) list $ drop 1 list

How to recurse through a list of tuples?

I am attempting to make a very simple program that finds the average distance a group of points is from 0. The input will be a group of tuples (i.e. (1,2) and (2,3)), it should calculate each points distance from 0 and then find the average.
I understand the logic and the general formula (again, it's very simple), which I have here:
averageDist ((x,y):xs) = (sqrt((x*x)+(y*y)))/length xs
I just don't understand the syntax for lists when using tuples. As you can see, I tried (x,y):xs and while it compiles, ghci thinks that all values are different types. How can I fix this program so I can iterate and apply the formula to each tuple?
I'm totally new to Haskell and I appreciate any and all help.
Thanks
First write an average function:
average :: [Double] -> Double
average xs = ...
and a distance function:
distance :: (Double,Double) -> Double
distance (x,y) = ...
Then you can use these functions together with map:
averageDistance :: [(Double,Double)] -> Double
averageDistance xs = average ( map distance xs )

Resources