14

例として、s のリストを合計する関数を実装したいとしますNum。コーディングの途中で、次の方法でデバッグしたいと思いDebug.Traceます。

module T where
import Debug.Trace

dosum :: (Num a) => [a] -> a
dosum xs = dosum' 0 xs
    where
        dosum' n [] = n
        dosum' n (x:xs) = trace (show n) $ dosum' (n+x) xs

問題は、これがコンパイルされないことです:

Could not deduce (Show a) arising from a use of dosum'
from the context (Num a)

デバッグが終了したら、追加(Show a)dosumてから削除できます (実際には、必ずしも にあるとは限らない型が必要ですがShow、整数でデバッグします)。関係する関数がいくつかあり、削除Show aステートメントを追加し続けると、これは面倒になる可能性があります。

機能が欲しいunsafeShow

unsafeShow :: a -> String

ある場合aは機能Show aし、そうでない場合は自由にクラッシュします。これは可能ですか?

4

6 に答える 6

13

いいえ、これは不可能です。それはパラメトリック性に違反します。ポリモーフィック関数は、呼び出される特定の型に基づいて異なる動作をすることはできません。Showまた、型のインスタンスを追加するとプログラムの動作が変わるという点で、オープン ワールドの前提が崩れます。

明示的に安全でないとマークされたものとして、これは便利なデバッグ支援になる可能性がありますが、GHC はそのような関数をサポートしておらず、現在の実装では簡単に関数を追加できるとは思いません。

これを行いたい同じ型クラスコンテキストを持つ多くの関数があり、概念的なセマンティックグループ化がある場合、可能な代替手段は、次のようなクラスを持つことです

class (Num a) => Number a
instance (Num a) => Number a

これは署名の代わりに使用でき、デバッグ時Numに宣言を に変更します。(Num a, Show a)(ただし、 よりも意味のある名前を選択する方がよいでしょうNumber!)

于 2012-04-18T14:40:43.270 に答える
10

本当にひどい答えはunsafeCoerceUnsafe.Coerceモジュールから使用することです。その名の通り、これは型システムをバイパスするための一般的なツールであり、間違っても型エラーや例外は発生せず、セグメンテーション違反が発生します。

この場合、型システムが整数であることを認識できるように、unsafeCoerce既に知っている値をIntegerto にすることができます。Integer次に、通常どおり表示できます (必ず明示的な型シグネチャを指定してください。これにより、表示されてshowいるものがわかりunsafeCoerceます。任意の型を返すことができるため、推測できません!)

unsafeCoerceしかし、誤ってon 以外のものでコードを呼び出した場合Integer、クラッシュ、メモリ破損など、何かが起こる可能性があります。セーフティ ネットを完全に捨ててしまったことになります。

一般に、唯一の「安全な」使用法は、既に等しいことunsafeCoerceがわかっている型の間ですが、型チェッカーはそうではありません (または他の特殊な使用例については、 docsを参照してください)。それでも、コメントでそれが唯一の選択肢である理由を説明しない限り、コードを読んでいる人はひどく眉をひそめます。

于 2012-04-18T15:28:05.933 に答える
3

これは不可能です。(注1 )


1 : 例外は、GHC のヒープのヒープ構造をa -> String関数経由でダンプできることです。たとえば、 vacuumを介して、常に値を 16 進数のポインター値に変換できます。これはあなたが望むものである可能性は低いです。この機能は、GHCi デバッガーが任意のヒープ値を表示するために使用するものと同じです。

于 2012-04-18T14:44:16.137 に答える
3

unsafeShow関数を純粋な Haskell で実装することはできません。GHC はそれを提供できますが、現在は提供していません。

ただし、GHCi デバッガーをチェックアウトすることもできます。Showこれにより、インスタンスを持たないものを出力できます。(さらに、他の方法では評価されないものを評価することを避けることができます。これは便利です。)

于 2012-04-18T14:45:40.660 に答える
1

通常は型シグネチャをコメントアウトしますが、関数がツリーの奥深くにある場合は煩わしくなります。書き換えルールを使用して、ポリモーフィック関数を変更されたバリアントに置き換えることができます。

-- original function, should add NOINLINE to make sure your rule gets a chance to fire.
{-# NOINLINE dosum #-}
dosum :: (Num a) => [a] -> a

-- a version with added debugging
dosumShow :: (Num a, Show a) => [a] -> a

{-# RULES "sub/dosum" forall x. dosum x = dosumShow x #-}
于 2012-04-18T16:16:33.073 に答える
0

GHCバージョン7.4.1ですか?それからリリースノート

Numクラスには、EqまたはShowスーパークラスがなくなりました。したがって、他の多くのクラスおよび関数は、それらを提供するためにNum制約に依存するのではなく、明示的なEqまたはShow制約を取得しています。

次の方法で、Haskell98/Haskell2010とGHCの両方で機能するコードを作成できます。

  • タイプのNumインスタンスを作成するときはいつでも、ShowインスタンスとEqインスタンスも作成し、

  • 関数、インスタンス、またはクラスにNum t制約を与えるときはいつでも、ShowtおよびEqt制約も与えます。

あなたのコードは以前のバージョンのGHCでうまく機能します(私は7.0.4で試します)。

于 2012-04-18T14:49:56.333 に答える