I'm trying to solve the Mini-Max Sum from HackerRank using Haskell. I'm just getting started with Haskell. Watched video's from #tsoding (youtube channel) and got inspired with his one line solutions to the problems.
I'm trying to provide a one-line solution to this problem. I'm following the 2nd approach from this youtube video:
- Find the minimum element in the array;
- Find the maximum element in the array;
- Calculate the sum of all the elements in the array;
- Calculate minimum by subtracting
max
fromsum
; and - Calculate maximum by subtracting
min
fromsum
.
This is what my code looks like so far:
main = interact $ show . foldr (-) 0 [minimum, maximum, sum] . map read . words
foldr (-) 0 [minimum, maximum, sum] (here is it possible to get the sum of numbers to be piped for foldr function?)
Even though my current code is wrong, I'm imagining the solution would look something like this. Could someone please help me with the syntax if this is possible?
The main issue in your code (and I think also what you were trying to solve) is that you're trying to collapse a list of functions by combining them with
(-) :: Num a => a -> a -> a
, which doesn't really make sense. If I understand correctly, what you want is to apply a single value (the input list) to every function in a list. There are multiple ways to do this, as explained in the answers to this recent SO question. With this simple trick, you're almost there. Here's the rest of the algorithm.For brevity's sake, I will use the following input list:
Using one of the methods from the linked SO question, you can feed this to every function in the list:
Then you can pattern match on the list to get the values you want:
One inconvenient of this
let-in
construct is that it doesn't allow for eta-reduction of thelist
variable, so you will either have to use a lambda or awhere
clause. For a function this long, I think a lambda isn't very readable, so I prefer awhere
clause:I modified your
main
function a bit, since what you want to print out is not the listshow list
, but every number in the list, separated by spaces:unwords $ map show list
. You can also think of this as the opposite of what you had done to get the list in the first place (map read . words
).Because this involves pattern-matching, I think it works better as a multi-line function, but there might be ways to solve it as a one-liner (other than making
f
a long and ugly lambda).EDIT
Here is a one-liner which uses arrows (from Control.Arrow) and the Applicative instance of
->
to feed the list to steps 4 and 5, and therefore avoid the long lambda:There is still some pattern-matching involved (to convert the tuple produced by
&&&
into a list), and I don't think it's more readable. Maybe there's a better way, but I don't really see it.