Project Euler Problem 18 (Haskell) - Maximum path sum I
I'll focus on maxPathSum as this is the core part of the algorithm.

The approach of zipWith max ys (tail ys) is correct and very nice, this is the essence of the recursive step.

But first, you're doing a lot of unnecessary computations at every step. In particular, you're reversing the argument list every time (reverse xs) and at the same time, you're computing its initial part (init . init $ xs), they're all O(n). If you instead start with an already reversed list, you can save all this effort, replacing O(n) init with O(1) tail, and O(n) ++ [...] with O(1) : ...:

maxPathSum2 :: [[Int]] -&gt; Int
maxPathSum2 = mps . reverse
  where
    maxPairs ys = zipWith max ys $ tail ys
    mps [[x]] = x
    mps sx = mps $ (zipWith (+) (maxPairs (head sx)) (sx !! 1)) : (tail . tail) sx


Note that placing maxPairs out of mps also helps the readability as it's now clear nothing there depends on sx.

Next thing is that you're combining the intermediate results with the data structure you're processing. While conceptually it isn't incorrect, in this case it makes the algorithm harder to understand and more complex. So let's add a parameter to mps that will hold the intermediate path lengths (and initialize it with an infinite list of 0s):

maxPathSum3 :: [[Int]] -&gt; Int
maxPathSum3 = mps (repeat 0) . reverse
  where
    maxPairs ys = zipWith max ys $ tail ys
    mps [r] [] = r
    mps rs (s:ss) = mps (zipWith (+) (maxPairs rs) s) ss


Not only this is much simpler;
notice that now we've just reinvented a fold over the list! We're consuming the list, passing the rest for further processing, and accumulating a result. Since we're consuming the elements from the start, this is a left fold. So let's rewrite it as

maxPathSum4 :: [[Int]] -&gt; Int
maxPathSum4 = head . foldl f (repeat 0) . reverse
  where
    maxPairs ys = zipWith max ys $ tail ys
    f rs s = zipWith (+) (maxPairs rs) s


But left fold over a reversed list is just a right fold. So we get

maxPathSum5 :: [[Int]] -&gt; Int
maxPathSum5 = head . foldr f (repeat 0)
  where
    maxPairs ys = zipWith max ys $ tail ys
    f s rs = zipWith (+) (maxPairs rs) s


And this is actually a very natural way how to express the solution: If we already know the longest paths in the part below a particular level (represented by rs and in recursive right-fold), we can compute the paths for this level as well.