4

私は Octave タイプを定義しています:

data Octave = 1 | 2 | 3
  deriving (Show, Read, Ord, Enum)

'1' はデータ コンストラクター識別子には有効ではないため、次のようにする必要があります。

data Octave = O1 | O2 | O3
  deriving (Show, Eq, Read, Ord, Enum)

ここで、show Octave O1「O1」が表示されますが、これはまさに私が望んでいるものではありません。結果を「1」にしたい。Show の動作を次のようにカスタマイズできることはわかっています。

instance Show Blabla where                                                                                       
  show (Blabla ints chars list num) =                                                                            
    "integers = " ++ show ints ++ "\n"

しかし、問題は、列挙型を使用していることです。つまり、識別子名「O1」以外の値がないことを意味します。Haskell でどのようにアクセスできますか?

別の質問: どうすれば読み返すことができますか?

read "O1" :: Octave動作しますが、欲しいですread "1" :: Octave

instance Read Octave where
  read "1" = O1
  read "2" = O2
  read "3" = O3

これは機能しません: " readis not a (visible) method of class Read".

4

5 に答える 5

6

Octave のEnumインスタンスを利用し、ShowReadインスタンスを使用して、次のIntように表示と読み取りを実装できます。

data Octave = O1 | O2 | O3 deriving (Eq, Ord, Enum)

instance Show Octave where
    show o = show (fromEnum o + 1)

instance Read Octave where
    readsPrec prec = map (\(n,s) -> (toEnum (n - 1), s)) . readsPrec prec

つまり、オクターブfromEnumと整数の間で<->と<->をtoEnum変換するため、読み取りと書き込みの両方で 1 ずつ調整する必要があります。O10O21

于 2013-09-04T08:37:02.450 に答える
4

必要なのはこれだけのようですね。

instance Show Octave where
  show O1 = "1"
  show O2 = "2"
  show O3 = "3"

3 つの句で定義showし、パターン マッチャにそれを理解させます。

于 2013-09-04T06:33:01.873 に答える
2

次のように、いつでも Int の既存のインスタンスを使用できます。

data Octave = O1 | O2 | O3 deriving (Enum,Bounded)

instance Show Octave where
   show = show . (+1) . fromEnum

instance Read Octave where
   readsPrec pr = map (\ (int,str) -> ((toEnum (int-1)),str) . readsPrec pr

これにより、O1..O3 が 1..3 として正しくレンダリングされ、読み戻されます。唯一の落とし穴は、4 のような別の整数を読み取ろうとする場合です。

*** Exception: toEnum{Octave}: tag (3) is outside of enumerations'range (0,2)

これは、より多くのコードを記述し、readsPred で有効な値を確認することで修正できます。

于 2013-09-04T07:17:46.370 に答える
1

識別子名にアクセスしたいようです。テンプレート haskellのようなものを使用してそれを行うこともできますが、これはひどい考えです。

実際、最初の悪い考えは、おそらく に依存することshowです。Showクラスは伝統的にデータを「シリアル化」するために使用されますが、Readクラスはデータを逆シリアル化します。出力をきれいに印刷したい場合は、独自のOctave -> String関数を作成することをお勧めします。そのためには、の結果に頼ることができshowます(そして結果を切り捨てます)。ただし、最も効率的な解決策は、 amalloyによって提案されているように、直接エンコードすることです。

于 2013-09-04T06:45:03.427 に答える