方法はありますが、きれいではありません。まず、型クラス インスタンスでディスパッチする関数を作成します。
class IsOrd a where
isOrd :: a -> IO Bool
isOrd
は最終的に 2 つのインスタンスを持ち、それぞれの に対応しますcase
。もちろん、シンプルに
instance Ord a => IsOrd a where
isOrd = putStrLn "Orderable!" >> return True
instance IsOrd a where
isOrd = putStrLn "Not orderable" >> return False
インスタンス ヘッド ( IsOrd
) が同じであるため機能しません。また、コンパイラの動作方法は、制約が保持されているかどうかに関係なくインスタンス ヘッドと一致し、その後でのみ制約をチェックするというものです。
ここから複雑な部分に入ります:こことここで説明されています。(2 番目のリンク、Oleg Kiselyov の Type Classes に関するコレクションには、関連する他の情報が含まれている可能性がありますが、それについてはまだ知らないため、ここには含めません。一般的には優れたリソースでもあります!)。その本質は次のようになります。
data HTrue
data HFalse
instance (Ord a) => IsOrd' HTrue a where
isOrd' _ x = putStrLn "Orderable." >> return True
instance IsOrd' HFalse a where
isOrd' _ x = putStrLn "Not orderable" >> return False
インスタンス ヘッドにタイプ レベルのブール値を追加して、例case
の s が個別のインスタンス ヘッドになるようにしました。かなりナイスなアイデア!
あなたが心配しなければならない他の詳細があり、その一部は完全には理解できませんが、とにかくそれを機能させるのは簡単です:ここにあなたが望むことをするいくつかのコードがあります (あなたはずっと Eq インスタンスをスレッド化する必要があります)制約もIsOrd
必要な場合は、それ以降)。Eq
最終結果は次のとおりです。
*Scratch> :l scratch.hs
[1 of 1] Compiling Scratch ( scratch.hs, interpreted )
Ok, modules loaded: Scratch.
*Scratch> isOrd (5::Int)
Orderable.
True
*Scratch> isOrd ('c')
Not orderable
False