(eval-when (:load-toplevel :compile-toplevel :execute)
(defun simple-lambda-list-p (lambda-list)
  (notany (lambda (x)
            (member x '(&optional &rest &key)))
          lambda-list))

(defmacro spicy-lambda ((&rest args) &body body)
  (assert (simple-lambda-list-p args) (args))
  (reduce (lambda (arg form)
            `(lambda (,arg) ,form))
          args :from-end t :initial-value `(progn ,@body)))

(defmacro defspicy (name (&rest args) &body body)
  (if (<= (length args) 1)
      `(defun ,name ,args ,@body)
      `(defun ,name (,(first args))
         (spicy-lambda ,(rest args) ,@body))))

(defun $-reader (stream subchar arg)
  (destructuring-bind (function &rest args) (read stream t nil t)
    (let ((init-expr
            `(,@(cond ((eq function 'funcall) `(funcall ,(pop args)))
                      ((eq function 'apply)   (error "`apply' is not implemented yet"))
                      ((symbolp function)     `(,function))
                      ((listp function)       `(funcall ,function)))
              ,@(and args `(,(pop args))))))
      (reduce (lambda (fn x) `(funcall ,fn ,x)) args :initial-value init-expr))))

(set-dispatch-macro-character #\# #\$ '$-reader))



(defspicy compose (f g x)
  (funcall f (funcall g x)))

(defspicy const (x y) x)

(defspicy plus (x y) (+ x y))

;; yoba dx = (dx +) . length
(defspicy yoba (dx)
  #$(compose (plus dx) 'length))

(map 'nil #$(compose 'print (yoba 111))
     '(() (1) (3 2 3)))