Skip to content

Instantly share code, notes, and snippets.

@alexy
Forked from hiredman/foo.clj
Created December 2, 2009 08:32
Show Gist options
  • Save alexy/247045 to your computer and use it in GitHub Desktop.
Save alexy/247045 to your computer and use it in GitHub Desktop.
(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