102 lines · 3.2 KB · Standard ML
RawDownload
(* Example: a simple example illustrating the difference between   generative and applicative functors and the motivation for supporting   both.   NB:     o A functor is generative when its formal argument is declared within   parenthesis, eg;   functor funid (modid:sigexp) = modexp;    o A functor is applicative when its formal argument   is declared *without* parentheses, eg:   functor funid modid:sigexp = modexp; *) (* Collection specifies a generic abstract type of collections *) signature Collection =    sig type elem	type collection        val empty : collection	val add : elem -> collection -> collection    end; (* We define two functor's that implement "Collection",    o The "Set" functor implements "Collections" using sets      represented as ordered lists.      Since the set representation depends on an element ordering:      it should vary with each ordering.     For this reason, the "Set" functor is implemented as a      "generative" functor.   o The "List" functor implements "Collections" using lists     The list representation does not depend on any element     ordering, and need not vary.     For this reason, the "List" functor is implemented as an      "applicative" functor.*)    (* "Set" functor should be generative because the return type    "collection" depends on the ordering "X.ord", which may vary with each   application of "Set" *) functor Set ( X:sig type elem val ord : elem * elem -> bool end )          (* ^ parentheses, "Set" is generative                  ^ *)   = struct 	type elem = X.elem	type collection = X.elem list	val empty = []	fun add e [] = [e]	  | add e (e'::c) =   	    if X.ord(e,e')		then e :: e' :: c	    else if X.ord(e',e)		     then 			 e :: c		 else e :: add e c    end :> Collection where type elem = X.elem;  structure IncSet = Set(struct type elem = int val ord = op <= end);structure DecSet = Set(struct type elem = int val ord = op >= end); (* because the functor "Set" is generative, "IncSet.collection" and   "DecSet.collection" are distinct types, eventhough "Set"'s argument   type "elem" = "int" was the same in both applications. *) (* val fail =  DecSet.add 2 (IncSet.add 1 IncSet.empty); *) (* The functor "List" is applicative since the type "collection"   depends only on the type "X.elem" (but not on any ordering on   "X.elem") *) functor  List X:sig type elem end      (* ^ no parentheses, "List" is applicative  ^ *)   = struct type elem = X.elem	   type collection = X.elem list	   val empty = []	   fun add e c = e::c    end :> Collection where type elem = X.elem; structure IncList = List(struct type elem = int val ord = op <= end);structure DecList = List(struct type elem = int val ord = op >= end);structure BoolList = List(struct type elem = bool end); (* because "List" is applicative "IncList.collection" and   "DecList.collection" are compatible types, because "List"'s   argument type "elem" = "int" is the same *) val ok =  DecList.add 2 (IncList.add 1 IncList.empty); (* but "BoolList.collection" is a different type, because the "List"'s   argument type "elem" = "bool" is distinct from "int" *) (* val fail = BoolList.add true (IncList.add 1 IncList.empty); *)