2008年10月4日土曜日

Haskell で代数的データ型の値を print で出力には

Python の __str__(), Ruby の inspect, Java の toString() に相当するものを実装したいときに、どうすればいいか忘れてしまったら、、、 ^^;

追記(2008.10.9) : 匿名さんに Show を deriving する方法について教えていただいた。

 

代数的データ型

他のデータ型を当該代数的データ型のコンストラクタで包んだデータをとする。 …

(例えば (Cons 1 '(2 3 4)) あるいは 1:[2,3,4]

(代数的データ型 – Wikipedia より)

 

方法を探す方法

ドキュメントの検索

例えば、「人」を表わす型が次のように定義されているとする。

data Person = Person {name :: String,
                      age :: Int} 

Haskell のドキュメントを検索 で print 関数を検索すると、自分で定義した型を Show クラスのインスタンスにして、show 関数を定義すればいいことがわかる。(cf. Haskell の show)、

 

エラーの内容と GHCi で当りをつける

もしくはお手軽に確認するのであれば、とりあえず print 関数を使うことだけは覚えているなら、

main = print (Person "Tarou" 20)

実行すると、

person.hs:4:7:
    No instance for (Show Person)
      arising from a use of `print' at person.hs:4:7-31
    Possible fix: add an instance declaration for (Show Person)
    In the expression: print (Person "Tarou" 20)
    In the definition of `main': main = print (Person "Tarou" 20)

 

コマンドラインにおいて ghci 、:t, :i を見ると、(cf. Haskell における関数の型と、部分適用)

Prelude> :t print
print :: (Show a) => a -> IO ()

Prelude> :i print
print :: (Show a) => a -> IO ()         -- Defined in System.IO

 

print 関数は、Show クラスのインスタンスにのみ適用可能なのがわかる。続いて Show についての情報を表示させると、

Prelude> :i Show
class Show a where
  showsPrec :: Int -> a -> ShowS
  show :: a -> String
  showList :: [a] -> ShowS
        -- Defined in GHC.Show

さすがにドキュメントを検索したときのように、次のような細かなことまではわからないのかな?

Minimal complete definition: showsPrec or show.

(Prelude より)

 

実装

data Person = Person {name :: String,
                      age :: Int} 

instance Show Person where
    show (Person name age) = "Person: " ++ name ++ ", " ++ show age

main = print (Person "Tarou" 20)

結果は、

Person: Tarou, 20

 

パターンマッチでは次のことを忘れずに。

data 宣言で宣言した型のフィールドにアクセスするには、データコンストラクタを使ったパターンマッチを利用します。

(ふつうのHaskellプログラミング , p226)


関連記事

3コメント:

匿名 さんのコメント...

data Person = Person {name :: String, age :: Int} deriving (Eq,Show)

とかやっておくと自分で書かなくても instance にしてくれますよ。

子馬 さんのコメント...
このコメントは投稿者によって削除されました。
子馬 さんのコメント...

Show クラスも deriving できたんですか。知りませんでした。ありがとうございます。 φ( ̄  ̄*) メモメモ

「ふつうの Haskell プログラミング」(p243) に「deriving 宣言が使える条件の詳細については Haskell 98 Report を参照してください。」とあったので、いつか見ておかねばと思いつつ、見てなかったのでこれを機に読もうと思ったのですが、自分にとっては書かれていることが難しくて... ^^;

とりあえず、導出インスタンス宣言の条件の 1 に 「C が Eq、Ord、Enum、 Bounded、Show あるいは Read のうちの どれか。 」とあったのでこの辺りを理解しないといけないということですよね。 CCC
( http://www.sampou.org/haskell/report-revised-j/derived.html )