Signatures ~ Types Structures ~ Variables Functors (special structure) ~ Functions (special value) * The module system (sig/struct) is incredibly powerful. * A signature is a spec. If you know Java, then signatures are *very* much like "Interfaces". Opaque vs Transparent: ---------------------- * When you ascribe a signature opaquely, the end-user is not allowed to do anything not in the signature. (* Fictitious data structure invented by Adam Megacz *) (* Lets you insert stuff and extract stuff in undefined order *) signature PILE = sig type 'a pile val empty : 'a pile val insert : 'a pile * 'a -> 'a pile val extract : 'a pile -> ('a * 'a pile) exception overdrawn end (* What if we use transparent ascription here? *) structure stack : PILE = struct type 'a pile = 'a list val empty = [] fun insert (element,p) = p::element exception overdrawn fun extract nil = raise overdrawn | extract (h::t) = (h,t) fun numelements nil = 0 | numelements (h::t) = 1 + numelements t end (* If we had used stack.empty, we would have been able to see - stack.empty; val it = [] : 'a stack.pile ^^ *) (* Give the var = val, 2 sided thing *) (* Or we can implement a pile as a queue *) structure queue :> PILE = struct type 'a pile = 'a list val empty = [] fun insert (element,p) = p::element exception overdrawn fun extract nil = raise overdrawn | extract (h::t) = (h,t) end (* Now, we can write a function that searches a graph, 15-211-style. As long as the function only relies on interfaces exposed by the PILE signature, it will work with either a queue or a stack *) (* Note we don't have access to the fact that 'a pile = 'a list: *) - stack.insert(stack.empty,1); val it = - : int stack.pile - it @ [1]; stdIn:148.1-148.9 Error: operator and operand don't agree [tycon mismatch] operator domain: 'Z list * 'Z list operand: int stack.pile * int list in expression: it @ 1 :: nil (* If we had implemented PILE like this: *) signature PILE = sig type 'a pile = 'a list val empty : 'a pile Val insert : 'a pile * 'a -> 'a pile val extract : 'a pile -> ('a * 'a pile) exception overdrawn end - stack.insert(stack.empty,1); val it = [1] : int stack.pile - it @ [1]; val it = [1,1] : int list (* Then Users would be able to access the actual list elements *)