Appearance
Provided type macros
tuple/tuple*
(tuple TYPES...) / (tuple* TYPES... TAIL)
emacs-lisp
(et (tuple 1 2 3))
;; -> (Cons 1 (Cons 2 (Cons 3 Nil)))
(et (&tuple 1 2 3))
;; -> (&Cons 1 (&Cons 2 (&Cons 3 Nil)))
(et (tuple* 1 2 3))
;; -> (Cons 1 (Cons 2 3))
(et (&tuple* 1 2 3))
;; -> (&Cons 1 (&Cons 2 3))args
(args SPECS...)
emacs-lisp
(et (args A B C))
;; -> &(A B C)
(et (args Integer &optional String &rest Any))
;; -> &(Integer . Nil | &(String . Any))
(et (args String &key :flag Boolean :count Integer))
;; -> &(String . &Plist<:flag Boolean, :count Integer>)fn
(fn [GENERICS?] ARGS RETURN)
emacs-lisp
(et (fn (args Integer String) Boolean))
;; -> (Function &(Integer String) Boolean)
(et (fn [T] (args T T T) List<T>))
;; -> (PolyFunction &(T T T) List<T>)fnN
(fnN ARGS... RETURN?)
The explicit return type can be omitted, in which case the return type will default to Any.
emacs-lisp
(et (fn0 Integer))
;; -> (Function Nil Integer)
(et (fn1 4 Integer))
;; -> (Function &(4 . Nil) Integer)
(et (fn2 4 3 Integer))
;; -> (Function &(4 3) Integer)
(et (fn1 4))
;; -> (Function &(4) Any)switch
(switch TYPE CASES...)
Each case is either
[TYPE OUTPUT][[GENERICS] PATTERN OUTPUT]
If the pattern and output happen to be the same, then you can use the shortcut:
[[GENERICS] PATTERN-AND-OUTPUT]
emacs-lisp
(et-defalias SumOf [(Nums <: &List<Number>)]
(switch Nums
[Nil 0]
[[T] &tuple<T> One]
[&List<Integer> Integer]
Number))
;; Expands to:
(extends? Nums Nil 0
(infer? Nums [T] &tuple<T> T
(extends? Nums &List<Integer> Integer
Number)))
(et-expand-aliases (et SumOf Nil))
;; -> 0
(et-expand-aliases (et SumOf (Cons 123 Nil)))
;; -> 123
(et-expand-aliases (et SumOf (tuple 2 3)))
;; -> Integer
(et-expand-aliases (et SumOf (tuple 1.5 2)))
;; -> NumberThe final case can be a single default type, which will be returned if no cases match. If a default type is not provided, Never will be used as the default.
map-cases
(map-cases TYPE CASES...)
One limitation of switch is that it is limited when the input is a union. map-cases is like switch, except cases can match partially. If a case matches only partially, the rest of the type will continue through the remaining cases, until the entire type has been matched.
If the cases collectively match the entire type, then the result will be the union of the outputs of the matching cases. If part of the type is not matched by any type, the result will be Never.
emacs-lisp
(et-defalias ExampleElementOf [Seq]
(map-cases Seq
[[T] &List<T> T]
[[T] Vector<T> T]
[BoolVector Boolean]))
(et-expand-aliases (et ExampleElementOf List<Integer>|Vector<Integer>))might-overlap?
(might-overlap? A B YES NO)
Evaluates to (extends? (supersect A B) Never NO YES)
If A and B have any chance of intersection, return YES, otherwise return NO.
If NO is omitted, it defaults to Never.
emacs-lisp
(et (might-overlap? Integer|String Boolean|String True Nil))
;; -> True
(et (might-overlap? Integer|String Boolean True Nil))
;; -> Nil
(et (might-overlap? Integer|String Boolean True))
;; -> Never
(et (might-overlap? Integer Positive True))
;; -> Truenon-nil
(non-nil A) -> (minus A Nil)
emacs-lisp
(et (non-nil List<Integer>))
;; -> (Integer . List<Integer>)