module Main (main) where

import TestUtils
import EvalIntExpr (testEvalIntExpr)
import EvalIdExpr (testEvalIdExpr)
import EvalMaybeExpr (testEvalMaybeExpr)
import PostfixExpr (testPostfixExpr)

– Implement toSingletonLists using map
toSingletonLists :: [e] -> [[e]]
toSingletonLists = map (:[])

– Implement listMap using list comprehension (kept as is, meets requirement)
listMap :: (a -> b -> c) -> a -> [b] -> [c]
listMap f a xs = [f a x | x <- xs]

– Implement member using foldl
member :: Eq e => e -> [e] -> Bool
member e = foldl (\acc y -> acc || y == e) False

– Implement selectNApart. Adjusted to select elements at intervals of n.
selectNApart :: Int -> [e] -> [e]
selectNApart _ [] = []
selectNApart n xs
  | n > 0 = take 1 xs ++ selectNApart n (drop n xs)
  | otherwise = []

– All tests set to Run. Simplified representation for demonstrative purposes.
allTests = [
    Run testToSingletonLists,
    Run testListMap,
    Run testMember,
    Run testSelectNApart,
    Run testEvalIntExpr,
    Run testEvalIdExpr,
    Run testEvalMaybeExpr,
    Run testPostfixExpr
  ]

main = do
  runTests allTests – Assuming runTests is a defined function that executes each test

– Placeholder for running tests. You need to define runTests, or adjust to your existing testing framework.
runTests :: [Test] -> IO ()
runTests tests = mapM_ ((Run test) -> test) tests – Placeholder function

data Test = Run (IO ()) – Simplified representation of a test. Adjust based on actual test implementation.  To implement `evalIntExpr`, you need to evaluate the expression tree according to the order of operations (also known as BODMAS or PEMDAS). This means that multiplication and division should be performed before addition and subtraction. Here's a possible implementation:
```haskell
evalIntExpr :: IntExpr -> Int
evalIntExpr (Leaf n)     = n
evalIntExpr (Add e1 e2)  = evalIntExpr e1 + evalIntExpr e2
evalIntExpr (Sub e1 e2)  = evalIntExpr e1 - evalIntExpr e2
evalIntExpr (Mul e1 e2)  = evalIntExpr e1 * evalIntExpr e2
evalIntExpr (Uminus e)   = negate (evalIntExpr e)
```
The above code recursively evaluates each node in the expression tree, starting from the leaves and moving upwards towards the root. The `negate` function is used to calculate the negative value for unary minus expressions.

Here are some explanations for your provided QuickCheck properties:

1. Commutativity: This checks whether adding or multiplying two integer values results in the same outcome regardless of their order. For example, `3+5` should give the same result as `5+3`.
2. Associativity: This checks whether multiple additions or multiplications can be grouped without affecting the final result. For instance, `(3+4)+5` should yield the same output as `3+(4+5)`. Similarly, `(3*4)*5` should produce the same result as `3*(4*5)`.
3. Subtraction: This verifies the identity property of subtraction, i.e., `a - b` equals `(-b) + a`.
4. Distributivity: This confirms the distribution law between multiplication and addition (or subtraction), meaning that multiplying a sum (difference) yields the same result as separately multiplying both terms and then adding (subtracting) them. Implement EvalIntExpr.hs function after selectNApart in the Main.hs program provided