インスタンスは、個々のコンストラクターではなく、型全体に対して定義されますFun
。そのため、型ではないことについて不平を言います。
全体的な目標は、のShow
インスタンスを持つことだと思いますA
。これは、関数が(一般に)インスタンスを持つことができないため、導出できませんShow
。ここにはいくつかのオプションがあります。
独自のShow
インスタンスを完全に記述します。
つまり、次のようなものです。
instance Show A where
show (Num n) = "Num " ++ show n
show (Fun _ s) = s
多くの場合、これが最も理にかなっています。Show
ただし、特に、多くのケースのうち1つだけが自動的に有効にならない複雑な再帰型では、派生したほうがよい場合がありますShow
。
派生A
可能にする:
派生できるのは、それ自体にインスタンスShow
があるタイプを含むタイプのみです。Show
のインスタンスがないためA -> A
、派生は機能しません。ただし、ある種のプレースホルダーを使用するものを作成することはできます。
instance Show (A -> A) where
show _ = "(A -> A)"
または、必要に応じて、空の文字列でもかまいません。
これにはFlexibleInstances
言語拡張が必要であることに注意してください; これは最も無害で一般的に使用される拡張機能の1つであり、複数のHaskell実装によってサポートされており、緩和される制限は(私の意見では)そもそも少しばかげているため、回避する理由はほとんどありません。
別のアプローチは、質問で述べたように、ラッパータイプを使用することです。これをより一般的にすることもできます:
data ShowAs a = ShowAs a String
instance Show (ShowAs a) where
show (ShowAs _ s) = s
...そしてコンストラクターで使用(ShowAs (A -> A))
します。Fun
これにより、ラップされたタイプを使用するときにいつでも追加のパターンマッチングを実行する必要があるため、少し厄介になりますが、表示方法などでコンテンツに「タグ付け」するための柔軟性が大幅に向上しますshowId = id `ShowAs` "id"
。