4

Can i somehow see what pattern haskell tries to use? It works on the smaller example, but crashes on the larger one, and I have a hard time finding what case it could be.

euler18 :: [[Integer]]
euler18 = pathPyr minipyr

pathPyr xss = path [(head xss)] (tail xss)

minipyr = [[3],[7,4],[2,4,6]]
pyramid = [[75], [95,64], [17,47,82], [18,35,87,10], [20,4,82,47,65], [19,1,23,75,3,34], [88,2,77,73,7,63,67], [99,65,4,28,6,16,70,92], [41,41,26,56,83,40,80,70,33], [41,48,72,33,47,32,37,16,94,29], [53,71,44,65,25,43,91,52,97,51,14], [70,11,33,28,77,73,17,78,39,68,17,57], [91,71,52,38,17,14,91,43,58,50,27,29,48], [63,66,4,68,89,53,67,30,73,16,69,87,40,31], [4,62,98,27,23,9,70,98,73,93,38,53,60,4,23]]

path :: [[Integer]] -> [[Integer]] -> [[Integer]]
path xss (ys:[])  = extendpath xss ys
path xss (ys:yss) = path (extendpath xss ys) yss

extendpath :: [[Integer]] -> [Integer] -> [[Integer]]
extendpath (xs:[]) (y1:y2:[]) = [y1:xs,y2:xs]
extendpath (xs:xss) (y1:y2:ys) = [y1:xs,y2:xs] ++ extendpath xss (y2:ys)

the output:

*Main> pathPyr pyramid 
[[4,63,91,70,53,41,41,99,88,19,20,18,17,95,75],[62,63,91,70,53,41,41,99,88,19,20,18,17,95,75],[62,66,91,70,53,41,41,99,88,19,20,18,17,95,75],[98,66,91,70,53,41,41,99,88,19,20,18,17,95,75],[98,66,71,70,53,41,41,99,88,19,20,18,17,95,75],[27,66,71,70,53,41,41,99,88,19,20,18,17,95,75],[27,4,71,70,53,41,41,99,88,19,20,18,17,95,75],[23,4,71,70,53,41,41,99,88,19,20,18,17,95,75],[23,4,71,11,53,41,41,99,88,19,20,18,17,95,75],[9,4,71,11,53,41,41,99,88,19,20,18,17,95,75],[9,68,71,11,53,41,41,99,88,19,20,18,17,95,75],[70,68,71,11,53,41,41,99,88,19,20,18,17,95,75],[70,68,52,11,53,41,41,99,88,19,20,18,17,95,75],[98,68,52,11,53,41,41,99,88,19,20,18,17,95,75],[98,89,52,11,53,41,41,99,88,19,20,18,17,95,75],[73,89,52,11,53,41,41,99,88,19,20,18,17,95,75],[73,89,52,11,71,41,41,99,88,19,20,18,17,95,75],[93,89,52,11,71,41,41,99,88,19,20,18,17,95,75],[93,53,52,11,71,41,41,99,88,19,20,18,17,95,75],[38,53,52,11,71,41,41,99,88,19,20,18,17,95,75],[38,53,38,11,71,41,41,99,88,19,20,18,17,95,75],[53,53,38,11,71,41,41,99,88,19,20,18,17,95,75],[53,67,38,11,71,41,41,99,88,19,20,18,17,95,75],[60,67,38,11,71,41,41,99,88,19,20,18,17,95,75],[60,67,38,33,71,41,41,99,88,19,20,18,17,95,75],[4,67,38,33,71,41,41,99,88,19,20,18,17,95,75],[4,30,38,33,71,41,41,99,88,19,20,18,17,95,75],[23,30,38,33,71,41,41,99,88,19,20,18,17,95,75]*** Exception: euler18.hs:(16,1)-(17,72): Non-exhaustive patterns in function Main.extendpath
Viktor Mellgren
  • 4,318
  • 3
  • 42
  • 75

5 Answers5

5
extendpath :: [[Integer]] -> [Integer] -> [[Integer]]
extendpath (xs:[]) (y1:y2:[]) = [y1:xs,y2:xs]
extendpath (xs:xss) (y1:y2:ys) = [y1:xs,y2:xs] ++ extendpath xss (y2:ys)

While it works, extendpath doubles the number of paths each time it's called. But the length of the rows increases only by 1. So as soon as you have a triangle with more than three rows, you get a pattern-match failure when processing the fourth (and every later) row.

After the second (zero-based, so the row with three elements) row, you have

--          LL   LR   RL   RR
extendpath [p_1, p_2, p_3, p_4] [v_1, v_2, v_3, v_4]
~> [v_1:p_1, v_2:p_1] ++ extendpath [p_2, p_3, p_4] [v_2, v_3, v_4]
~> [v_1:p_1, v_2:p_1] ++ [v_2:p_2, v_3:p_2] ++ extendpath [p_3, p_4] [v_3, v_4]
~> [v_1:p_1, v_2:p_1] ++ [v_2:p_2, v_3:p_2] ++ [v_3:p_3, v_4:p_3] ++ extendpath [p_4] [v_4]

and the last call has no matching pattern.

Now, the paths p_2 and p_3 end in the same place, so the two can be extended by the same two values in the next row, but extendpath doesn't take into account where a path ends. Generally, on the n-th row there are

n `choose` k

paths ending in the k-th spot [that's why I chose zero-based counting here]. When extending paths, the possible extensions depend on the current end point of the path.

You need a different approach. Especially for problem 67.

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
4

You have tons and tons of cases that aren't covered. This means that you have partial functions, which are bad. Try to avoid them as much as possible. Often, it's easy to convert them into total functions using the Maybe type constructor. Then you can use pattern matching to make sure all cases are covered. Also, note that head and tail are partial functions.

As a hack to diagnose this, I'd just add something like:

extendPath xs ys = error ("oops, pattern-match failed, arguments were: " ++ show xs ++ show ys)

Make sure that that case goes after the other ones, because it's a catch-all.

You'll have to do this for path and pathPyr, too. You may want to recruit Haskell's help by turning on warnings.

Matt Fenwick
  • 48,199
  • 22
  • 128
  • 192
  • Thank you! I know it is partial but since i know the structure i don't have to have all cases. Although obviously it seems like some case was missed – Viktor Mellgren Mar 27 '13 at 13:28
  • @Vixen not to sound glib, but if you know the structure then why was a case missed? Help Haskell help you -- use its awesome type system to find the errors for you! – Matt Fenwick Mar 27 '13 at 13:36
2

You can make GHC/GHCi give you a warning when there's incomplete patterns by giving -W as an argument to GHC, or entering :set -W in GHCi (and recompiling/reloading your file!).

yatima2975
  • 6,580
  • 21
  • 42
  • I don't think this answers the question. The OP already knows the functions have incomplete patterns, but doesn't know when/what exactly triggers the error. – Matt Fenwick Mar 27 '13 at 15:41
  • @MattFenwick: I only saw Vixens comment on your answer after I had posted mine! There's also something to be said for preventing the error instead of patching up the symptoms... – yatima2975 Mar 27 '13 at 16:14
2

A good error warning level would give you all the info you need. To trigger it, put in the head of your files:

{-# OPTIONS_GHC -Wall #-}

This will warn you about a bunch of other stuff too, most probably. Which is good.

m09
  • 7,490
  • 3
  • 31
  • 58
  • I don't think this answers the question. The OP already knows the functions have incomplete patterns, but doesn't know when/what exactly triggers the error. – Matt Fenwick Mar 27 '13 at 15:41
  • Yup it doesn't exactly gives the info OP asks for. It IMHO gives the info the OP needs, aka stick to a good error level and listen to what GHC tells you since if you do you won't encounter the problem in the first place. – m09 Mar 27 '13 at 15:47
0

Another option to catch missing patterns:

http://community.haskell.org/~ndm/catch/

Viktor Mellgren
  • 4,318
  • 3
  • 42
  • 75