Sun October 09, 2011
■[Haskell] 型エラーとして FizzBuzz を出力
GHC で以下のコードをコンパイルしようとすると,型エラーとして FizzBuzz 的なものが出力されます.
出力を見やすくしようとして Template Haskell を使ったら比較的最近の GHC でないとコンパイルできなくなってしまった…
手元の GHC (7.0.3) だと OK で,ideone の GHC (6.8.2) だとダメ*1だった.
#define N 30
のところでいくつまで出力するかを決めている.
N を大きくしたら -fcontext-stack の値も大きくしないと別のエラーが出る.
{-# LANGUAGE TypeFamilies, EmptyDataDecls, TypeOperators, UndecidableInstances #-} {-# LANGUAGE TemplateHaskell, CPP #-} {-# OPTIONS_GHC -fcontext-stack=64 #-} import Language.Haskell.TH data Z data S n data Yes data No data Nil data x ::: xs type family a :<= b :: * type instance Z :<= Z = Yes type instance Z :<= S b = Yes type instance S n :<= Z = No type instance S a :<= S b = a :<= b type family a :== b :: * type instance Z :== Z = Yes type instance Z :== S b = No type instance S a :== Z = No type instance S a :== S b = a :== b type family a :- b :: * type instance a :- Z = a type instance S a :- S b = a :- b type Divisible a b = Divisible' (a :<= b) a b type family Divisible' t a b :: * type instance Divisible' Yes a b = a :== b type instance Divisible' No a b = Divisible (a :- b) b data Fizz data Buzz data FizzBuzz #define N 30 type family ToReadable x :: * type instance ToReadable Fizz = Fizz type instance ToReadable Buzz = Buzz type instance ToReadable FizzBuzz = FizzBuzz $( let cls = mkName "ToReadable" f i = let name = mkName ('N' : show i) nat = foldr appT (conT (mkName "Z")) $ replicate i (conT (mkName "S")) in [dataD (cxt []) name [] [] [], tySynInstD cls [nat] (conT name)] in sequence $ concatMap f [1 .. N] ) type ToFizzBuzz n = ToFizzBuzz' (Divisible n (S (S (S Z)))) (Divisible n (S (S (S (S (S Z)))))) n type family ToFizzBuzz' t3 t5 n :: * type instance ToFizzBuzz' No No n = ToReadable n type instance ToFizzBuzz' Yes No n = Fizz type instance ToFizzBuzz' No Yes n = Buzz type instance ToFizzBuzz' Yes Yes n = FizzBuzz type FizzBuzzList n = FizzBuzzList' n n type family FizzBuzzList' n i :: * type instance FizzBuzzList' n Z = Nil type instance FizzBuzzList' n (S i) = (ToFizzBuzz (n :- i)) ::: (FizzBuzzList' n i) class ShowType a where showType :: a main = let _ = showType :: FizzBuzzList $(foldr appT (conT (mkName "Z")) $ replicate N (conT (mkName "S"))) in return ()
出力例:
(snip)
No instance for (ShowType
(N1
::: (N2
::: (Fizz
::: (N4
::: (Buzz
::: (Fizz
::: (N7
::: (N8
::: (Fizz
::: (Buzz
::: (N11
::: (Fizz
::: (N13
::: (N14
::: (FizzBuzz
::: (N16
::: (N17
::: (Fizz
::: (N19
::: (Buzz
::: (Fizz
::: (N22
::: (N23
::: (Fizz
::: (Buzz
::: (N26
::: (Fizz
::: (N28
::: (N29
::: (FizzBuzz
::: Nil)))))))))))))))))))))))))))))))
arising from a use of `showType'
(snip)
*1:tySynInstD が無いらしい
トラックバック - http://d.hatena.ne.jp/eagletmt/20111009/1318177425
リンク元
- 121 http://d.hatena.ne.jp/JavaBlack/20111009/p3
- 58 http://t.co/ZY2HV7Es
- 12 http://twitter.com/
- 11 http://t.co/9PpOgA6M
- 8 http://t.co/qoFjj3J1
- 7 http://d.hatena.ne.jp/JavaBlack/20111009
- 7 http://t.co/bx8z3wLW
- 6 http://reader.livedoor.com/reader/
- 5 http://k.hatena.ne.jp/keywordblog/Haskell
- 4 http://t.co/bDgueuXJ
