{-# LANGUAGE DeriveDataTypeable #-}
module Data.Combinator.SKI where

import Data.Data (Data)
import Data.Typeable (Typeable)
import Test.QuickCheck
import Control.Applicative

data SKI = S | K | I | Ap SKI SKI
    deriving (Eq, Ord, Data, Typeable)

-- | >>> Ap (Ap S K) K
-- ``skk
-- >>> Ap (Ap (Ap S I) I) (Ap (Ap S I) I)
-- ```sii``sii
instance Show SKI where
    showsPrec d = showParen (app_prec < d) . f where
        f S = showChar 's'
        f K = showChar 'k'
        f I = showChar 'i'
        f (Ap x y) = showChar '`' . shows x . shows y
        app_prec = 10

instance Arbitrary SKI where
    arbitrary = frequency
        [ (,) 1 $ pure S
        , (,) 1 $ pure K
        , (,) 1 $ pure I
        , (,) 2 $ Ap <$> arbitrary <*> arbitrary
        ]

instance CoArbitrary SKI where
    coarbitrary = coarbitrary . show
