-- Example
{-# LANGUAGE TemplateHaskell #-}

import Conjure
import Test.LeanCheck


-- This was inspired by the These datatype from the cathis package.
-- https://hackage.haskell.org/package/cathis
-- This is an extension of the type there with the added None constructor.
data These a b  =  None | This a | That b | These a b
  deriving (Eq, Ord, Show, Read)

isThis :: These a b -> Bool
isThis (This _)  =  True
isThis (These _ _)  =  True
isThis _  =  False

fromThis :: These a b -> a
fromThis (This x)  =  x
fromThis (These x _)  =  x

isThat :: These a b -> Bool
isThat (That _)  =  True
isThat (These _ _)  =  True
isThat _  =  False

fromThat :: These a b -> b
fromThat (That y)  =  y
fromThat (These _ y)  =  y


deriveConjurable ''These


fromThese' :: A -> B -> These A B -> (A, B)
fromThese' 0 1 None  =  (0, 1)
fromThese' 0 1 (This 2)  =  (2,1)
fromThese' 0 1 (That 2)  =  (0,2)
fromThese' 0 1 (These 1 0)  =  (1,0)

listhese' :: These A A -> [A]
listhese' (These 1 2)  =  [1,2]
listhese' (This 1)  =  [1]
listhese' (That 2)  =  [2]

cathis' :: [These A B] -> [A]
cathis' [This 0, This 1]  =  [0,1]
cathis' [None, That 0]  =  []
cathis' [This 0, None, That 1]  =  [0]
cathis' [This 0, These 0 1]  =  [0,0]
cathis' [These 0 1, None, This 0]  =  [0,0]

cathat' :: [These A B] -> [B]
cathat' [This 0, This 1]  =  []
cathat' [None, That 0]  =  [0]
cathat' [This 0, None, That 1]  =  [1]
cathat' [That 0, These 0 1]  =  [0,1]

cathese' :: [These A A] -> [A]
cathese' [This 0, This 1]  =  [0,1]
cathese' [None, That 0]  =  [0]
cathese' [This 0, None, That 1]  =  [0,1]
cathese' [This 0, These 0 1]  =  [0,0,1]
cathese' [These 0 1, That 2]  =  [0,1,2]

main :: IO ()
main  =  do
  conjure "fromThese" fromThese'
    [ prim "," ((,) :: A -> B -> (A,B))
    ]

  conjure "listhese" listhese'
    [ pr ([] :: [A])
    , prim ":" ((:) :: A -> [A] -> [A])
    ]

  conjure "cathis" cathis'
    [ pr ([] :: [A])
    , prim ":" ((:) :: A -> [A] -> [A])
    , prim "isThis" (isThis :: These A B -> Bool)
    , prim "fromThis" (fromThis :: These A B -> A)
    , prif (undefined :: [A])
    ]

  conjure "cathat" cathat'
    [ pr ([] :: [B])
    , prim ":" ((:) :: B -> [B] -> [B])
    , prim "isThat" (isThat :: These A B -> Bool)
    , prim "fromThat" (fromThat :: These A B -> B)
    , prif (undefined :: [B])
    ]

  -- couldn't make this reachable, I didn't try much...
  conjureWith args{target = 1080} "cathese" cathese'
    [ pr ([] :: [A])
    , prim ":" ((:) :: A -> [A] -> [A])
    , prim "++" ((++) :: [A] -> [A] -> [A])
    , prim "isThis" (isThis :: These A A -> Bool)
    , prim "fromThis" (fromThis :: These A A -> A)
    , prim "isThat" (isThat :: These A A -> Bool)
    , prim "fromThat" (fromThat :: These A A -> A)
    -- , prif (undefined :: A)
    , prif (undefined :: [A])
    ]
  -- expected functionality
  -- these []  =  []
  -- these (This x : ts)  =  x : these ts
  -- these (That y : ts)  =  y : these ts
  -- these (These x y : ts)  =  x : y : these ts