{-# LANGUAGE TemplateHaskell, TypeOperators #-}

module Data.Thorn.FunctorExample (module Data.Thorn.FunctorExample) where

import Data.Thorn
import Data.Char
import Data.Functor.Contravariant
import Data.Bifunctor
import Data.Profunctor

type a :<- b = b -> a
nuf :: Char
nuf = $(autofmap [t|(:<-)|]) chr ord (+1) 'a' -- 'b'
varnuf :: [Variance]
varnuf = $(autovariance [t|(:<-)|]) -- [Co,Contra]

data Cntr a = Cntr (a -> Int)
autofunctorize [t|Cntr|] -- instance Contravariant Cntr where ...

tuple :: (Int,Int,Int)
tuple = $(autofmap $[t|(,,) Int|]) (+1) (+2) (0,0,0) -- (0,1,2)
vartuple :: [Variance]
vartuple = $(autovariance [t|(,,) Int|]) -- [Co,Co]

data FunFun a b = FunFun ((b -> a) -> b)
varfunfun :: [Variance]
varfunfun = $(autovariance [t|FunFun|]) -- [Contra,Co]
autofunctorize [t|FunFun|] -- instance Profunctor FunFun where ...

data What a b c = What1 c (a -> c) | What2 a
varwhat :: [Variance]
varwhat = $(autovariance [t|What|]) -- [Fixed,Free,Co]
autofunctorize [t|What T0|]
-- instance Bifunctor (What a) where ... and
-- instance Profunctor (What a) where ...

data List a = Nil | a :* (List a) deriving Show
fromNormalList :: [a] -> List a
fromNormalList [] = Nil
fromNormalList (a : as) = a :* fromNormalList as
toNormalList :: List a -> [a]
toNormalList Nil = []
toNormalList (a :* as) = a : toNormalList as
list :: [Int]
list = toNormalList $ $(autofmap [t|List|]) (+10) (fromNormalList [1..5]) -- [11..15]
varlist :: [Variance]
varlist = $(autovariance [t|List|]) -- [Co]
autofunctorize [t|List|] -- instance Functor List where ...

data Rose a = Rose a (Forest a) deriving Show
data Forest a = Forest [Rose a] deriving Show
gorose n = Rose n (Forest (replicate n (gorose (n-1))))
rose = $(autofmap [t|Rose|]) (+1) (gorose 2)
varrose, varforest :: [Variance]
varrose = $(autovariance [t|Rose|]) -- [Co]
varforest = $(autovariance [t|Forest|]) -- [Co]
autofunctorize [t|Rose|] -- instance Functor Rose where ...
autofunctorize [t|Forest|] -- instance Functor Forest where ...