-
-
Save alexy/247045 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defn sig [x] | |
(:sig (meta (resolve x)))) | |
(defmulti type-of (comp type first list)) | |
(defmethod type-of :function [thing & _] (sig thing)) | |
(defmethod type-of java.util.List [expr & a] | |
(conj (map #(type-of % (first a)) (rest expr)) | |
(type-of (vary-meta (first expr) assoc :type :function)))) | |
(defmethod type-of clojure.lang.Symbol [s & a] | |
(if-let [c ((first a) s)] | |
c | |
(type s))) | |
(defmethod type-of :default [thing & _] | |
(type thing)) | |
(defmulti reduce-types type) | |
(defmethod reduce-types Class [expr] expr) | |
(defmethod reduce-types java.util.List [expr] | |
(assert (isa? (vec (map reduce-types (rest expr))) (-> expr first first))) | |
(-> expr first last)) | |
(defn sig->args "for creating a map of argument names to type" [s a] | |
(into {} (map vector a (first s)))) | |
(defmacro deft [name sig args & code] | |
(assert (= (count (first sig)) (count args))) | |
(let [resolved-sig (list (into [] (map resolve (first sig))) (resolve (last sig))) | |
sa (sig->args resolved-sig args) | |
code-type (reduce-types (type-of (last code) sa))] | |
(assert (= code-type (last resolved-sig))) | |
`(defn ~(with-meta name {:sig `(quote ~resolved-sig)}) ~args ~@code))) | |
(alter-meta! #'* assoc :sig (list [Number Number] Number)) | |
(alter-meta! #'+ assoc :sig (list [Number Number] Number)) | |
(alter-meta! #'char assoc :sig (list [Object] Character)) | |
(deft add ([Number, Number] Number) [a b] (+ a b)) | |
(deft mult ([Number, Number] Number) [a b] (* a b)) | |
(deft num->char ([Number] Character) [b] (char b)) | |
;;this also works because char's :sig says it excepts an Object and (isa? Integer Object) | |
(deft int->char ([Integer] Character) [b] (char b)) | |
;;this throws an exception in you try and define it | |
;;add returns a Number but int->char takes an Integer | |
(deft sum-and-char ([Number Number] Character) [a b] (int->char (add a b))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment