In tro duction to F unctional Programming: Lecture 9 1 In tro duction to F unctional Programming John Harrison Univ ersit y of Cam bridge Lecture 9 ML examples I: Sym b olic Di�eren tiation T opics co v ered: � Sym b olic computation � Data represen tation � Prett yprin ting � Di�eren tiation � Simpli�cation b y rewriting John Harrison Univ ersit y of Cam bridge, 3 F ebruary 1998
In tro duction to F unctional Programming: Lecture 9 2 Sym b olic computation This co v ers applications where manipulation of mathematical expr essions , in general con taining v ariables, is emphasized at the exp ense of actual n umerical calculation. There are sev eral successful `computer algebra systems' suc h as Axiom, Maple and Mathematica, whic h can do certain sym b olic op erations that are useful in mathematics. Examples include factorizing p olynomials and di�eren tiating and in tegrating expressions. W e will sho w ho w ML can b e used for suc h applications. Our example will b e sym b olic di�eren tiation. This will illustrate all the t ypical comp onen ts of sym b olic computation systems: data represen tation, in ternal algorithms, parsing and prett yprin ting. John Harrison Univ ersit y of Cam bridge, 3 F ebruary 1998
In tro duction to F unctional Programming: Lecture 9 3 Data represen tation W e will allo w mathematical expressions to b e built up from v ariables and constan ts b y the application of n -ary op erators. Therefore w e de�ne a recursiv e t yp e as follo ws: - datatype term = Var of string | Const of string | Fn of string * (term list); F or example the expression sin ( x + y ) =cos ( x � exp ( y )) � l n (1 + x ) is represen ted b y: Fn("-", [Fn("/",[Fn("sin",[Fn("+",[Var "x", Var "y"])]), Fn("cos",[Fn("-",[Var "x", Fn("exp", [Var "y"])])])]), Fn("ln",[Fn("+",[Const "1", Var "x"])])]); John Harrison Univ ersit y of Cam bridge, 3 F ebruary 1998
In tro duction to F unctional Programming: Lecture 9 4 The need for parsing and prin ting Reading and writing expressions in their ra w form is rather unpleasan t. This is a general problem in all sym b olic computation systems. T ypically one w an ts: � A p arser to accept input in h uman-readable form and translate it in to the in ternal represen tation � A pr ettyprinter to translate output from the in ternal represen tation bac k to a h uman-readable form. W e will use parsing as another ma jor example of functional programming, so w e will defer that for no w. Ho w ev er w e will no w write a simple prin ter for our expressions. John Harrison Univ ersit y of Cam bridge, 3 F ebruary 1998
In tro duction to F unctional Programming: Lecture 9 5 Prett yprin ting expressions Ho w do w e w an t to prin t expressions? � V ariables and constan ts are just written as their names. � Ordinary n -ary functions applied to argumen ts are written b y juxtap osing the function and a brac k eted list of argumen ts, e.g. f ( x ; : : : ; x ). 1 n � In�x binary functions lik e + are written in b et w een their argumen ts. � Brac k ets are used where necessary for disam biguation. � In�x op erators ha v e a notion of precedence to reduce the need for brac k ets. John Harrison Univ ersit y of Cam bridge, 3 F ebruary 1998
In tro duction to F unctional Programming: Lecture 9 6 Storing precedences W e can ha v e a list of binary op erators together with their precedences, e.g. - val infixes = [("+",10), ("-",10), ("*",20), ("/",20)]; This sort of list, asso ciating data with k eys, is called an asso ciation list . T o get the data asso ciated with a k ey w e use the follo wing: - fun assoc a ((x,y)::rest) = if a = x then y else assoc a rest; In our case, w e de�ne: - fun get_precedence s = assoc s infixes; This pro cedure of linear searc h is ine�cien t, but it is simple and adequate for small examples. T ec hniques lik e hashing are b etter for hea vyw eigh t applications. John Harrison Univ ersit y of Cam bridge, 3 F ebruary 1998
In tro duction to F unctional Programming: Lecture 9 7 Making precedences mo di�able Because of static binding, c hanging the list of in�xes do es not c hange get precedence . Ho w ev er w e can mak e infixes a reference instead and then it is mo di�able: - val infixes = ref [("+",10), ("-",10), ("*",20), ("/",20)]; ... - fun get_precedence s = assoc s (!infixes); > val get_precedence = fn : string -> int - get_precedence "^"; ! Uncaught exception: ! Match - infixes := ("^",30)::(!infix es ); > val it = () : unit - get_precedence "^"; > val it = 30 : int This setup is not purely functional, but is p erhaps more natural. John Harrison Univ ersit y of Cam bridge, 3 F ebruary 1998
In tro duction to F unctional Programming: Lecture 9 8 Finding if an op erator is in�x W e will treat an op erator as in�x just if it app ears in the list of in�xes with a precedence. W e can do: - fun is_infix s = (get_precedence s; true) handle _ => false; b ecause get_precedence fails on non-in�xes. An alternativ e co ding is to use an auxiliary function can whic h �nds out whether the application of its �rst argumen t to its seconds succeeds:: - fun can f x = (f x; true) handle _ => false; > val can = fn : ('a -> 'b) -> 'a -> bool - val is_infix = can get_precedence; > val is_infix = fn : string -> bool John Harrison Univ ersit y of Cam bridge, 3 F ebruary 1998
In tro duction to F unctional Programming: Lecture 9 9 The prin ter: explanation The prin ter consists of t w o m utually recursiv e functions. The function string_of_term tak es t w o argumen ts. The �rst is a `curren tly activ e precedence', and the second is the term. F or example, in prin ting the righ t-hand argumen t of x * (y + z) , the curren tly activ e precedence is the precedence of * . If the function prin ts an application of an in�x op erator (here + ), it puts brac k ets round it unless its o wn precedence is higher. W e ha v e a second, m utually recursiv e, function, to prin t a list of terms separated b y commas. This is for the argumen t lists of non-unary and non-in�x functions of the form f ( x ; : : : ; x ). 1 n John Harrison Univ ersit y of Cam bridge, 3 F ebruary 1998
In tro duction to F unctional Programming: Lecture 9 10 The prin ter: co de - fun string_of_term prec = fn (Var s) => s | (Const c) => c | (Fn(f,args)) => if length args = 2 andalso is_infix f then let val prec' = get_precedence f val s1 = string_of_term prec' (hd args) val s2 = string_of_term prec' (hd(tl args)) val ss = s1^" "^f^" "^s2 in if prec' <= prec then "("^ss^")" else ss end else f^"("^(string_of_terms args)^")" and string_of_terms tms = case tms of [] => "" | [t] => string_of_term 0 t | (h::t) => (string_of_term 0 h)^","^ (string_of_terms t); John Harrison Univ ersit y of Cam bridge, 3 F ebruary 1998
In tro duction to F unctional Programming: Lecture 9 11 The prin ter: installing Mosco w ML has sp ecial facilities for installing user-de�ned prin ters in the toplev el read-ev al-prin t lo op. Once our prin ter is installed, an ything of t yp e term will b e prin ted using it. - load "PP"; > val it = () : unit - fun print_term pps s = let open PP in begin_block pps INCONSISTENT 0; add_string pps ("`"^(string_of_te rm 0 s)^"`"); end_block pps end; > val print_term = fn : ppstream -> term -> unit - installPP print_term; > val it = () : unit John Harrison Univ ersit y of Cam bridge, 3 F ebruary 1998
Recommend
More recommend