{-# LANGUAGE
    MultiParamTypeClasses,
    RankNTypes,
    ScopedTypeVariables,
    FlexibleInstances,
    FlexibleContexts,
    UndecidableInstances,
    IncoherentInstances,
    PolyKinds,
    LambdaCase,
    MonomorphismRestriction #-}

module Comb where

class Comb repr where
  app :: repr (a -> b) -> repr a -> repr b
  s :: repr ((a -> b -> c) -> (a -> b) -> (a -> c))
  k :: repr (a -> b -> a)
  i :: repr (a -> a)
  b :: repr ((b -> c) -> (a -> b) -> (a -> c))
  c :: repr ((a -> b -> c) -> (b -> a -> c))
  w :: repr ((a -> a -> b) -> (a -> b))

newtype Eval x = Eval {unEval :: x}

instance Comb Eval where
  app (Eval f) (Eval x) = Eval (f x)
  s = Eval (\f x arg -> f arg $ x arg)
  k = Eval const
  i = Eval id
  b = Eval (.)
  c = Eval flip
  w = Eval (\f x -> f x x)

newtype SShow x = SShow {unSShow :: String}

instance Comb SShow where
  app (SShow f) (SShow x) = SShow $ "(" ++ f ++ " " ++ x ++ ")"
  s = SShow "s"
  k = SShow "k"
  i = SShow "i"
  b = SShow "b"
  c = SShow "c"
  w = SShow "w"

main :: IO ()
main = return ()