Skip to content

Instantly share code, notes, and snippets.

@myuon
Created August 10, 2014 06:21
Show Gist options
  • Save myuon/cd6113ca89df4b49411e to your computer and use it in GitHub Desktop.
Save myuon/cd6113ca89df4b49411e to your computer and use it in GitHub Desktop.
GHC.TypeLitsと型レベルFizzBuzz ref: http://qiita.com/myuon_myon/items/dc6184f8e3d06ce3126c
{-# LANGUAGE DataKinds, TypeOperators, KindSignatures, TypeFamilies #-}
{-# LANGUAGE UndecidableInstances, FlexibleInstances, FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables, GADTs, MultiParamTypeClasses, FunctionalDependencies #-}
import GHC.TypeLits
import Data.Type.Equality
import Data.Proxy
type family (a :: Nat) % (b :: Nat) :: Nat where
a % b = Mod a b (CmpNat a b)
type family Mod (a :: Nat) (b :: Nat) (k :: Ordering) :: Nat where
Mod a b EQ = 0
Mod a b LT = a
Mod a b GT = Mod (a-b) b (CmpNat (a-b) b)
data FizzBuzzFlag = FizzBuzz | Fizz | Buzz | Natural Nat
class ShowFB (f :: FizzBuzzFlag) where
showFB :: Proxy f -> String
instance ShowFB FizzBuzz where showFB _ = "FizzBuzz"
instance ShowFB Fizz where showFB _ = "Fizz"
instance ShowFB Buzz where showFB _ = "Buzz"
instance (KnownNat n) => ShowFB (Natural n) where showFB _ = show $ natVal $ (Proxy :: Proxy n)
type family ToFizzBuzz (a :: Nat) :: FizzBuzzFlag where
ToFizzBuzz a = ToFizzBuzz' a (a % 3) (a % 5)
type family ToFizzBuzz' (a :: Nat) (b3 :: Nat) (b5 :: Nat) :: FizzBuzzFlag where
ToFizzBuzz' a 0 0 = FizzBuzz
ToFizzBuzz' a 0 b5 = Fizz
ToFizzBuzz' a b3 0 = Buzz
ToFizzBuzz' a b3 b5 = Natural a
fizzbuzz :: (ShowFB (ToFizzBuzz n)) => Proxy (n :: Nat) -> String
fizzbuzz (Proxy :: Proxy m) = showFB $ (Proxy :: Proxy (ToFizzBuzz m))
{-
class FizzBuzzList (n :: Nat) where
fizzbuzzList :: Proxy n -> [String] -> [String]
Overlapping instances for FizzBuzzList 0
arising from a use of ‘fizzbuzzList’
Matching instances:
instance FizzBuzzList 0 -- Defined at TypedFizzBuzz.hs:39:10
instance (ShowFB (ToFizzBuzz n), FizzBuzzList (n - 1)) =>
FizzBuzzList n
-- Defined at TypedFizzBuzz.hs:41:10
instance FizzBuzzList 0 where
fizzbuzzList _ acc = acc
instance (ShowFB (ToFizzBuzz n), FizzBuzzList (n-1)) => FizzBuzzList n where
fizzbuzzList x@(Proxy :: Proxy n) acc = fizzbuzzList (Proxy :: Proxy (n-1)) (fizzbuzz x : acc)
-}
class FizzBuzzList' (b :: Bool) (n :: Nat) where
fizzbuzzList' :: Proxy b -> Proxy n -> [String] -> [String]
instance FizzBuzzList' True 0 where
fizzbuzzList' _ _ acc = acc
instance (ShowFB (ToFizzBuzz n), FizzBuzzList' (n == 1) (n-1)) => FizzBuzzList' False n where
fizzbuzzList' _ k@(Proxy :: Proxy n) acc = fizzbuzzList' (Proxy :: Proxy (n == 1)) (Proxy :: Proxy (n-1)) ((fizzbuzz k) : acc)
fizzbuzzList :: (FizzBuzzList' (n==0) n) => Proxy (n :: Nat) -> [String]
fizzbuzzList x@(Proxy :: Proxy n) = fizzbuzzList' (Proxy :: Proxy (n==0)) x []
main = do
putStrLn $ fizzbuzz (Proxy :: Proxy 100)
mapM_ putStrLn $ fizzbuzzList (Proxy :: Proxy 10)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment