10

В настоящее время я имею дело с некоторым кодом Haskell, который я не писал, но что я внес изменения. После того, как мои изменения, я запускаю программу и получить следующее сообщение об ошибке:Могу ли я использовать OverlappingInstances для получения более приятных сообщений об ошибках?

Prelude.!!: index too large 

Вызов !! не в моем коде, поэтому рефакторинга прочь больше работы, чем я хочу делать, если я могу избежать его ,

То, что я хотел бы, чтобы сделать что-то вроде этого:

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.!! 

т.е. функции !! определяются для каждого возможного типа списка, но он ведет себя по-разному каждый раз, когда шоу экземпляр определяется для данного типа элемента.

В качестве альтернативы, метод tryShow :: a -> Maybe String также сделает трюк.

Есть ли способ сделать это? Могу ли я заставить OverlappingInstances использовать реализацию по умолчанию только тогда, когда реализация Show не применяется? Это гарантированное поведение?

EDIT: бонусные баллы для всех, кто может получить ошибку, также распечатать сообщение, подобное трассе.

ответ

8

Вам не нужно перекрывающихся экземпляров, просто использовать отладчик GHC на собственном (!!): сессии

{-# 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:

> :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

Это был отличный, и, конечно, «реальный мир» ответ. Но я все равно люблю видеть, есть ли способ получить поведение экземпляров, о которых я говорю. – jmite