; Convenience flow control macros
(defmacro when (condition body-head &rest body)
  "If condition is true, evaluates the expressions in body, otherwise returns nil"
  `(if ,condition (progn ,body-head ,@body))
  )

(defmacro unless (condition body-head &rest body)
  "If condition is false, evaluates the expressions in body, otherwise returns nil"
  `(if (not ,condition) (progn ,body-head ,@body))
  )

; Result handling functions
(defun result/ok? (x)
  "Returns #t if x is an ok"
  (= 'ok (car x))
  )
(defun result/err? (x)
  "Returns #t if x is an error"
  (= 'err (car x))
  )
(defun result/map (f x)
  "If x is an ok, applies f to its value, otherwise does nothing"
  (if (result/ok? x)
    `(ok ,(f (cadr x)))
    x
    )
  )
(defun result/map-err (f x)
  "If x is an error, applies f to its value, otherwise does nothing"
  (if (result/err? x)
    `(err ,(f (cadr x)))
    x
    )
  )

; Convenience error handling macros
(defmacro catch (expression error-symbol handler)
  "Evaluates expression, running the handler if evaluation fails, introducing error-symbol as error"
  (let (eval-result-symbol (gensym))
    `(let (,eval-result-symbol (eval (quote ,expression)))
       (cond
         ((result/ok? ,eval-result-symbol) (cadr ,eval-result-symbol))
         (&otherwise
           (let (,error-symbol (cadr ,eval-result-symbol))
             ,handler
             )
           )
         )
       )
    )
  )

(defmacro compile-debug (expression)
  "Prints the input expression during macro expansion/compile time and evaluates the expression in runtime"
  (print expression)
  expression
  )
(defmacro runtime-debug (expression)
  "Prints the input expression and evaluates it in runtime"
  `(progn
     (print (quote ,expression))
     ,expression
     )
  )

; Convenience list functions
(defun cadr (x) "Alias for (car (cdr x))" (car (cdr x)))
(defun cdar (x) "Alias for (cdr (car x))" (cdr (car x)))
(defun caddr (x) "Alias for (car (cdr (cdr x)))" (car (cdr (cdr x))))
(defun cadar (x) "Alias for (car (cdr (car x)))" (car (cdr (car x))))
