-- higher.hs: conjuring higher order functions
--
-- Copyright (C) 2024-2025 Rudy Matela
-- Distributed under the 3-Clause BSD licence (see the file LICENSE).
import Conjure

appSpec :: ((Int -> Int) -> Int -> Int) -> [Property]
appSpec ($)  =
  [ property (((+1) $ 2) == 3)
  , property ((abs $ (-2)) == 2)
  , property ((negate $ 1) == -1)
  ]

composeSpec :: ((Int->Int) -> (Int->Int) -> Int->Int) -> [Property]
composeSpec (.)  =
  [ property $ ((*2) . (*3)) 1 == 6
  , property $ (abs . negate) 7 == 7
  , property $ (negate . abs) 8 == -8
  ]

flipSpec :: ((Int -> Int -> Int) -> Int -> Int -> Int) -> [Property]
flipSpec flip  =
  [ property $ flip const 1 2 == 2
  , property $ flip div 2 10 == 5
  , property $ flip mod 3 10 == 1
  ]

mapSpec :: ((Int -> Int) -> [Int] -> [Int]) -> [Property]
mapSpec map  =
  [ property $ map (*2) [1,2,3] == [2,4,6]
  , property $ map abs [0,-1,-2] == [0,1,2]
  ]

foldSpec :: ((Int -> Int -> Int) -> Int -> [Int] -> Int) -> [Property]
foldSpec fold  =
  [ property $ fold (+) 0 [1,2,3] == 6
  , property $ fold (*) 1 [1,2,3] == 6
  , property $ fold (+) 0 [1,2,3,4] == 10
  , property $ fold (*) 1 [1,2,3,4] == 24
  ]

filterSpec :: ((Int -> Bool) -> [Int] -> [Int]) -> [Property]
filterSpec filter  =
  [ property $ filter (<0) [0,1,-1,2,-2] == [-1,-2]
  , property $ filter (>0) [0,1,-1,2,-2] == [1,2]
  , property $ filter odd [0,1,2,3,4,5,6] == [1,3,5]
  , property $ filter even [0,1,2,3,4,5,6] == [0,2,4,6]
  ]

main :: IO ()
main = do
  conjureFromSpec "$"      appSpec     ingredients
  conjureFromSpec "."      composeSpec ingredients
  conjureFromSpec "flip"   flipSpec    ingredients
  conjureFromSpec "map"    mapSpec     ingredients
  conjureFromSpec "fold"   foldSpec    ingredients
  conjureFromSpec "filter" filterSpec  ingredients


ingredients :: [Ingredient]
ingredients  =
  [ con ([] :: [Int])
  , fun ":" ((:) :: Int -> [Int] -> [Int])
  , guard
  ]
