perhaps for my application, the only reasonable thing is to define the syntax so that the user gives a lambda-list, a possibly-empty map, and a function body. The map will map variable names to type restrictions. But I could also examine the meta data of the lambda-list for additional, very simple, type hints which are limited to a symbol (which is a common case).
(destructuring-case (some-function-call)
[^Boolean a [^String b c] & ^Boolean d] {}
(println [:first a b c d])
[^Boolean a b] {b (or String Boolean)}
(println [:second a b])
[a b] {a (and Number (not Long))
b (or String Boolean)}
(println [:third a b])