How to extract multiple elements from a list and do something with them?

Hello,
parallel to Exercism i use Hackerrank to practice at work.
At this i am really struggeling with the 2D Array data structures challange. The following code should solve the problem, but unfortunately does not compile.

hourglassSum arr = do
    sumAndMax unpack2DArray arr
      
unpack2DArray [] = []    
unpack2DArray (head : tail) =
    append1DArray (head (unpack2DArray tail))
    
append1DArray (head : []) tail2 = 
    head : tail2
append1DArray (head : tail) tail2 =
    append1DArray tail tail2
    
sumAndMax arr
    case arr of
        (a:b:c:_:_:_:_:d:_:_:_:_:e:f:g:[]) -> a+b+c+d+e+f+g
        (a:b:c:_:_:_:_:d:_:_:_:_:e:f:g:_) ->
            let prev = sumAndMax (Data.List.tail (arr))
            let cur = a+b+c+d+e+f+g
            if cur > prev then
                cur
            else
                prev

If i were to use pattern matching in the function signature of “sumAndMax”, i do not know how to take the whole list and pass it on for recursion. Therefore, i want to extract the data later, sum it and then call the recursion. How can i achieve this?

The posted code has some syntax issues:

-sumAndMax arr
+sumAndMax arr =
-            let prev = sumAndMax (Data.List.tail (arr))
+            let prev = sumAndMax (Data.List.tail (arr)) in
-            let cur = a+b+c+d+e+f+g
+            let cur = a+b+c+d+e+f+g in

There are also some type errors, some with obvious fixes and some with less obvious ones. I recommend always giving type signatures for global definitions and non-trivial local definitions, because they greatly help finding logic errors.


The HackerRank problem is about a 2D structure. I do not know off the top of my head how to solve it with a flat list (if that is even – reasonably – possible). A complicating factor is that the array is not guaranteed to be a certain size. You probably want to use a [[Int]] or an Array (Int, Int) Int instead. Indexing can be done with !! (list, partial), !? (list, total), and ! (array, partial).

The first solution that comes to my mind goes

(code provided in an attempt to communicate approach to problems generally)

maxHourglassSum array = maximum hourglassSums
  where
    hourglassSums :: [Int]
    hourglassSums = map sum hourglasses

    hourglasses :: [[Int]]
    hourglasses = map hourglassAt coordinates

    coordinates = _  -- where are all the hourglasses?
    hourglassAt coordinate = _  -- an indexing feast

I’m not seeing what to recurse on here, sorry. Are there ways of combining subsolutions into larger solutions?

In the problem specification of the 2d Array it is guaranteed that the input is 6 by 6.
The input is a list of lists. Because the recursive natrue of lists in Haskell is new to me, i try to use it as much as possible. With indexing, i could probably solve the problem within a blink of an eye.

The recursion should lie in the sumAndMax function. If the input array is large enough, call the same function with the tail of the array, until the array has reached a certain length. Basically, by omitting the head in the next recursion, i shift the indices by one to the right. If the sum is greater then the previous one, use this sum, else use the previous.

What does the in Keyword do? The Haskell Wiki article about keywords does not really help: Keywords - HaskellWiki. I also did not encurter it in any Haskell book so far.

Ah, I missed that.

Assuming that the array be represented as a [[Int]], this might look like

sumAndMax (firstRow : secondRow : thirdRow : rest) =
  maxHourglassSumInRows firstRow secondRow thirdRow
  `max`
  sumAndMax (secondRow : thirdRow : rest)  -- recursion
sumAndMax _ = minBound  -- base cases

Does that help?

I still haven’t been able to come up with a flat list approach.

Just like then and else, in never comes alone: it is part of the let … in _ expression.

let expressions are similar in purpose to where clauses. The differences are

  • let expressions are expressions, so you can do whatever with them:
    _ = 3 * (let x = 5 in x + x) `div` 2
    
    You cannot do anything like this with where clauses, which are stuck to declarations and case expressions.
  • let expressions list the local definitions before the main expression, whereas where clauses list them after.

let’s and where’s purposes are the same: allowing local definitions.

Inside do blocks let does occur alone, but that is syntactic sugar for let … in _:

_ = do
  actions
  let value = computation
  moreActions value
-- which means
_ = actions >> let value = computation in moreActions value

The let _ = _ that is sometimes seen in GHCi contexts (example in LYAH) is actually the one from do notation. GHCi is special like that. A REPL in an language without true variables is a bit weird.