This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

MM notes

  • Loading branch information...
1 parent c6e2172 commit 40bda88af57725b153a56e7f4df18449ff9e0e81 @frenchy64 committed Apr 19, 2012
Showing with 104 additions and 0 deletions.
  1. +104 −0 notes/multimethods.txt
View
@@ -0,0 +1,104 @@
+; # Type checking Clojure multimethods, using occurrence typing
+;
+; Problem: Type check the definition of a multimethod
+; Issues: Probably difficult to type check the caller of a multimethod
+; to guarantee a matching dispatch method. Simpler if the dispatch
+; is on the Class of its arguments.
+;
+; We can utilize the result of the dispatch function to refine
+; the types of arguments mentioned.
+;
+; If we are dispatching on the Class of our arguments, we can type
+; check the caller of our multimethod. Otherwise, it's probably too
+; strict to throw a type error.
+
+;record type
+(defrecord MyRecord [[Species :- Keyword]
+ [other :- Keyword]])
+
+;2 instances
+(def b1 (map->MyRecord {:Species :Bunny :other :stuff}))
+(def b2 (map->MyRecord {:Species :Bunny :other :stuff}))
+
+
+; It's unlikely that we know the :Species value
+; for both b1 and b2 at the function call: (encounter b1 b2)
+; so it's probably too strict to throw a type error at this point
+; if we cannot find a matching MM dispatch method.
+(encounter b1 b2)
+-> :mate
+
+; read as: encounter is a MM that takes 2 MyRecords and returns a Keyword
+(+T encounter [MyRecord MyRecord -> Keyword])
+(defmulti encounter
+ (fn [x y]
+ ; Inferred Types:
+ ; b :- (MyRecord [:Species Keyword] [:other Keyword])
+ ; l :- (MyRecord [:Species Keyword] [:other Keyword])
+ [(:Species x) (:Species y)]))
+
+(defmethod encounter [:Bunny :Lion]
+ [b l]
+ ; Inferred Types
+ ; b :- (MyRecord [:Species :Bunny] [:other Keyword])
+ ; l :- (MyRecord [:Species :Lion] [:other Keyword])
+ (if (and (= (:Species b)
+ :Bunny) ; always true, from type of b
+ (= (:Special l)
+ :Lion)) ; always true, from type of l
+ :run-away
+ 'not-a-keyword)) ; impossible case, should type check
+
+(defmethod encounter [:Rabbit :Fox] ; we can refine the type of b and l
+ [b l]
+ ; Inferred Types
+ ; b :- (MyRecord [:Species :Rabbit] [:other Keyword])
+ ; l :- (MyRecord [:Species :Fox] [:other Keyword])
+ (if (and (= (:Species b)
+ :Rabbit) ; always true, from type of b
+ (= (:Special l)
+ :Fox)) ; always true, from type of l
+ :run-away
+ 'not-a-keyword)) ; impossible case, should type check
+
+; # Similarities to Occurrence Typing
+;
+; Occurrence typing refines types by keeping track of the results of function calls
+; that tell us information about a variable.
+;
+; eg. (let [x (number-or-string)]
+; (if (number? x)
+; (+ x 1) ; x is a number
+; (str x 1))) ; x is a string
+;
+; This requires type predicates like `number?` be annotated with extra information
+; to help the type refinement.
+;
+; We can consider a multimethod similar to a nested conditional.
+
+(let [x x
+ y y]
+ (cond
+ (= [:Bunny :Lion]
+ [(:Species x) (:Species y)])
+ (if (and (= (:Species b)
+ :Bunny)
+ (= (:Special l)
+ :Lion))
+ :run-away
+ 'not-a-keyword)
+
+ (= [:Bunny :Fox]
+ [(:Species x) (:Species y)])
+ (if (and (= (:Species b)
+ :Rabbit)
+ (= (:Special l)
+ :Fox))
+ :run-away
+ 'not-a-keyword)
+
+ :else
+ (throw ....)))
+
+; This should be straightforward to typecheck with occurrence typing.
+; I assume Typed Racket is able to track the elements of a map.

0 comments on commit 40bda88

Please sign in to comment.