{-
Following a suggestion by oleg@okmij.org, 2010-08-06
-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverlappingInstances #-}
module Control.Arrow.Let where

import Control.Arrow (Arrow, arr, (&&&), (<<<), (^<<), (^>>), (>>^), )


class Index t envi envo where
    ref :: Arrow arr => arr envi t -> arr envo t

instance Index t envi (t,envi) where
    ref _ = arr fst

instance Index t envi envo => Index t envi (h,envo) where
    ref (ai :: arr envi t)  = snd ^>> (ref ai :: arr envo t)


infixl 1 <<<&

(<<<&) :: Arrow arrow =>
   arrow (b,a) c -> arrow a b -> arrow a c
x <<<& y  =  x <<< y &&& arr id


input :: Arrow arrow => arrow () Int
f :: Arrow arrow => arrow (Int,()) Char
g :: Arrow arrow => arrow (Char,(Int,())) Bool

input = undefined
f = undefined
g = undefined


c1 :: Arrow arrow => arrow (Int,()) Bool
c1 = let inp1 = ref input >>^ ( > 1)
	 inp2 = ref f >>^ ( == 'a')
     in  (uncurry (&&) ^<< inp1 &&& inp2) <<<& f

c2 :: Arrow arrow =>
      arrow (Int,()) Bool
c2 = let inp1 = ref input >>^ ( > 1)
	 inp2 = ref f >>^ (== 'a')
	 h    = uncurry (||) ^<< ref g &&& (uncurry (&&) ^<< inp1 &&& inp2)
     in  h <<<& g <<<& f