10

私は現在、私が書いたのではなく、変更を加えたいくつかの Haskell コードを扱っています。変更後、プログラムを実行すると、次のエラー メッセージが表示されます。

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

つまり、関数!!は考えられるすべてのリスト タイプに対して定義されますが、要素タイプに対して Show インスタンスが定義されるたびに異なる動作をします。

あるいは、tryShow :: a -> Maybe Stringメソッドもこのトリックを実行します。

これを行う方法はありますか?Show の実装が適用されない場合にのみ、OverlappingInstances にデフォルトの実装を使用させることはできますか? これは保証された動作ですか?

編集:エラーを取得してスタックトレースのようなメッセージを出力できる人にはボーナスポイント!

4

1 に答える 1

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
于 2015-11-21T08:45:07.780 に答える