-- count.hs: conjuring an element count function
--
-- 2021-2025 Rudy Matela
import Conjure

-- an idiomatic count without using filter
count :: Eq a => a -> [a] -> Int
count x  =  c
  where
  c []  =  0
  c (y:ys)  =  (if x == y then 1 else 0) + c ys

count' :: A -> [A] -> Int
count' 0 [0]  =  1
count' 0 [1]  =  0
count' 1 [0]  =  0
count' 1 [1]  =  1
count' 0 [0,0]  =  2
count' 0 [0,1]  =  1
count' 0 [1,2]  =  0
count' 1 [0,0]  =  0
count' 1 [0,1]  =  1
count' 1 [1,2]  =  1
count' 0 [0,0,0]  =  3
count' 0 [0,0,1]  =  2
count' 0 [1,0,0]  =  2

main :: IO ()
main = do
  -- count x xs  =  length (filter (== x) xs)
  --                1       2       3  4  5
  conjure "count" count'
    [ fun "length" (length :: [A] -> Int)
    , fun "filter" (filter :: (A -> Bool) -> [A] -> [A])
    , fun "==" ((==) :: A -> A -> Bool)
    ]

  -- count x []  =  0
  -- count x (y:xs)  =  count x xs + (if x == y then 1 else 0)
  conjure "count" count'
    [ con (0 :: Int)
    , con (1 :: Int)
    , fun "+" ((+) :: Int -> Int -> Int)
    , fun "==" ((==) :: A -> A -> Bool)
    , iif (undefined :: Int)
    ]

  -- a little bit larger, guards are only allowed at the root
  -- so there is a need to repeat the recursive call twice
  conjure "count" count'
    [ con (0 :: Int)
    , con (1 :: Int)
    , fun "+" ((+) :: Int -> Int -> Int)
    , fun "==" ((==) :: A -> A -> Bool)
    , guard
    ]
