10

Ich beschäftige mich derzeit mit Haskell Code, den ich nicht geschrieben habe, aber an dem ich Änderungen vorgenommen habe. Nach meinen Änderungen, betreiben ich das Programm und die folgende Fehlermeldung:Kann ich OverlappingInstances verwenden, um bessere Fehlermeldungen zu erhalten?

Prelude.!!: index too large 

Der Aufruf von !! ist nicht in meinem Code, so dass es Refactoring weg ist mehr Arbeit, als ich tun möchte, wenn ich es vermeiden kann .

Was Ich mag würde, ist so etwas wie dies zu tun:

class PrintList a where 
    (!!) :: [a] -> Int -> a 

instance (Show a) => PrintList a where 
    l (!!) n = if n < (length l) 
      then (l Prelude.!! n) 
      else error ("Index " ++ show n ++ " out of bounds in " ++ show l) 

instance PrintList a where 
    (!!) = Prelude.!! 

das heißt die Funktion !! für jeden möglichen Listentyp definiert ist, aber es verhält sich anders, wenn eine Karte Instanz für den Elementtyp definiert ist.

Alternativ würde eine tryShow :: a -> Maybe String Methode auch den Trick tun.

Gibt es eine Möglichkeit, dies zu tun? Kann ich OverlappingInstances zwingen, die Standardimplementierung nur zu verwenden, wenn die Show-Implementierung nicht zutrifft? Ist das garantiertes Verhalten?

BEARBEITEN: Bonuspunkte für alle, die den Fehler erhalten können, um auch eine Stack-Trace-ähnliche Nachricht zu drucken!

Antwort

8

Sie brauchen nicht überlappende Instanzen, benutzen Sie einfach den GHC Debugger auf Ihrer eigene (!!):

{-# OPTIONS -Wall -O0 #-} 
module Debugger3 where 

import qualified Prelude as P 
import Prelude hiding ((!!)) 

(!!) :: [a] -> Int -> a 
xs !! n = 
    xs P.!! n -- line 9 

foo :: Int -> Int 
foo n = [0..n] !! 3 

bar :: Int -> Int 
bar n = foo (n-3) 

main :: IO() 
main = print (bar 4) 

GHCi Sitzung:

> :l Debugger3 
[1 of 1] Compiling Debugger3  (Debugger3.hs, interpreted) 
Ok, modules loaded: Debugger3. 
*Debugger3> :break 9 
Breakpoint 1 activated at Debugger3.hs:9:4-18 
*Debugger3> :trace main 
Stopped at Debugger3.hs:9:4-18 
_result :: a = _ 
n :: Int = 3 
xs :: [a] = _ 
[Debugger3.hs:9:4-18] *Debugger3> :force xs 
xs = [0,1] 
[Debugger3.hs:9:4-18] *Debugger3> :history 
-1 : !! (Debugger3.hs:(8,1)-(9,18)) 
-2 : foo (Debugger3.hs:12:9-19) 
-3 : foo (Debugger3.hs:12:1-19) 
-4 : bar (Debugger3.hs:15:9-17) 
-5 : bar (Debugger3.hs:15:1-17) 
-6 : main (Debugger3.hs:18:15-19) 
-7 : main (Debugger3.hs:18:8-20) 
<end of history> 
[Debugger3.hs:9:4-18] *Debugger3> :back 
Logged breakpoint at Debugger3.hs:(8,1)-(9,18) 
_result :: a 
[-1: Debugger3.hs:(8,1)-(9,18)] *Debugger3> :back 
Logged breakpoint at Debugger3.hs:12:9-19 
_result :: Int 
n :: Int 
[-2: Debugger3.hs:12:9-19] *Debugger3> n 
1 
+0

Dies war ausgezeichnet, und ist sicherlich die "reale Welt" Antworten. Aber ich würde immer noch gerne sehen, ob es einen Weg gibt, das Instanzenverhalten zu erreichen, von dem ich rede. – jmite