6
data A = Num Int
     | Fun (A -> A) String deriving Show

instance Show (Fun (A -> A) String) where
  show (Fun f s) = s

それを出力する関数の属性が欲しいA -> Aので、にString型パラメーターがありますFun。これをghciにロードすると、

/home/kmels/tmp/show-abs.hs:4:16:
    Not in scope: type constructor or class `Fun'

これは、新しいデータ型を追加することで達成できると思います

data FunWithAttribute = FA (A -> A) String 

の追加data A = Num Int | Fun FunWithAttributeと書き込みinstance Show FunWithAttribute。追加のデータ型は回避できますか?

4

3 に答える 3

11

インスタンスは、個々のコンストラクターではなく、型全体に対して定義されます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"

于 2013-02-12T19:22:36.357 に答える
5

おそらく私はあなたが求めているものに従っていません。しかし、上記のコードは、コンパイルするために次のように書くことができます。

data A = Num Int
     | Fun (A -> A) String 

instance Show A where
  show (Fun f s) = s
  show (Num i) = show i

いくつかの説明

コンストラクター(Fun)のshowインスタンスを作成しようとしているようです。クラスインスタンスは、データ型全体に対して書き込まれます(例外ある場合があります、dunno)。したがって、インスタンスの一部として、各コンストラクターに一致する1つのショーを作成する必要があります。NumとFunは、それぞれデータ型Aのコンストラクターです。

また、deriving各コンストラクターの各パラメーターが、この場合はのメンバーでない限り、使用できませんShow。さて、あなたの例はそれがしたいので少し特別Show (A -> A)です。関数を表示する方法は、他の応答でいくらか説明されていますが、網羅的な方法はないと思います。他の例は、実際にはタイプまたはプレースホルダーを「表示」するだけです。

于 2013-02-12T19:17:43.053 に答える
4

インスタンス(または任意のクラスインスタンス)は、型コンストラクターShowではなく、データ型に対して定義する必要があります。つまり、あなたは単に必要です

instance Show A where

どうやら、あなたはこのインスタンスをで取得しようとしていますが、derivingHaskellが表示する方法を知らないため、それは機能しませんA->A。今ではその関数を表示したくないようですが、deriving Showインスタンスは常に利用可能なすべての情報を表示するため、それを使用することはできません。

あなたの問題に対する明白で最良の解決策はworldsayshiのものです:まったく使用derivingしないでください、しかしあなた自身で適切なインスタンスを定義してください。または、の疑似インスタンスを定義してから、次のA->A派生を使用することもできます。

{-# LANGUAGE FlexibleInstances      #-}

data A = Num Int | Fun (A->A) String   deriving(Show)

instance Show (A->A) where  show _ = ""

これは次のように機能します

Prelude> Fun (const $ Num 3) "bla"
Fun  "bla"
于 2013-02-12T19:22:26.050 に答える