リストを作る

amachang

a> 「[]」も「:」も型構築子なんだよ!
n> な、なんだってー!

という会話をしたので自分メモ。amchangのエントリーにトラックバックするつもりだったのにamachangは書き上げないまま晩ご飯を食べに行ってしまった(><)

下のコードは全部同じ結果を返す。

-- main = print [1, 2, 3]
-- main = print $ 1:2:3:[]
-- main = print $ (:) 1 ((:) 2 ((:) 3 []))

下のコードは1:2:3:[]と出力する。

data MyList = Cons{car::Int, cdr::MyList} | Empty

instance Show MyList where 
    show Empty = "[]"
    show (Cons x y) = show x ++ ":" ++ show y

main = print $ Cons 1 (Cons 2 (Cons 3 Empty)) 
-- 1:2:3:[]

なるほど、なるほど。でもせっかくだから同じ出力にしたいな。

ata MyList = Cons{car::Int, cdr::MyList} | Empty

instance Show MyList where 
    show Empty = "[]"
    show (Cons x y) = "[" ++ show_ (Cons x y)

show_ (Cons x Empty) = show x ++ "]"
show_ (Cons x y) = show x ++ "," ++ show_ y

main = print $ Cons 1 (Cons 2 (Cons 3 Empty)) 
-- [1,2,3]

できた!

で、せっかくだから本物のリストと同じようにいろいろなものが入るようにしようと思って下のように書いたらエラー

data MyList a = Cons{car::a, cdr::(MyList a)} | Empty
    `MyList' is not applied to enough type arguments
    Expected kind `*', but `MyList' has kind `* -> *'
    In the instance declaration for `Show MyList'

「In the instance declaration for `Show MyList'」と言われているので「instance Show MyList」を「instance Show MyList a」にしてみた。またエラー。

    Kind error: `Show' is applied to too many type arguments
    In the instance declaration for `Show MyList a'

「too many type arguments」と言われているので「instance Show (MyList a)」にしてみた。またエラー。

    Could not deduce (Show a) from the context (Show (MyList a))
      arising from use of `show_' at tmp.hs:5:29-44
    Possible fix: add (Show a) to the class or instance method `show'
    In the second argument of `(++)', namely `show_ (Cons x y)'
    In the expression: "[" ++ (show_ (Cons x y))
    In the definition of `show':
	show (Cons x y) = "[" ++ (show_ (Cons x y))

うーん。わからないのでグーグル先生に聞いてみる。
第15回 Haskellでのデバッグのコツをつかむ:ITpro

VarListのShowクラスのインスタンスを定義する際,型変数aにShow aという文脈を制約として付ける必要があることに注意してください。VarList構成子の第1引数xに対してshowメソッドを使っているため, Showクラスのインスタンスでは型変数aもShowクラスのインスタンスである必要があります。この制限が定義から抜けているとエラーが表示されます。

おお、書いてあるとおりに変更したらできた!

data MyList a = Cons{car::a, cdr::(MyList a)} | Empty

instance (Show a) => Show (MyList a) where 
    show Empty = "[]"
    show (Cons x y) = "[" ++ show_ (Cons x y)

show_ (Cons x Empty) = show x ++ "]"
show_ (Cons x y) = show x ++ "," ++ show_ y

main = print $ Cons 'a' (Cons 'b' (Cons 'c' Empty)) 
-- ['a','b','c']

data (Show a) => MyList a = ...ではなぜダメなのかはよくわからない。