DOC PREVIEW
UW CSE 341 - Lecture Notes

This preview shows page 1-2-3 out of 9 pages.

Save
View full document
View full document
Premium Document
Do you want full access? Go Premium and unlock all 9 pages.
Access to all documents
Download any document
Ad free experience
View full document
Premium Document
Do you want full access? Go Premium and unlock all 9 pages.
Access to all documents
Download any document
Ad free experience
View full document
Premium Document
Do you want full access? Go Premium and unlock all 9 pages.
Access to all documents
Download any document
Ad free experience
Premium Document
Do you want full access? Go Premium and unlock all 9 pages.
Access to all documents
Download any document
Ad free experience

Unformatted text preview:

CSE341, Fall 2011, Lecture 12 SummaryStandard Disclaimer: This lecture summary is not necessarily a complete substitute for attending class,reading the associated code, etc. It is designed to be a useful resource for students who attended class andare later reviewing the material.We start by showing how ML modules can be used to separate bindings into different namespaces. We thenbuild on this material to cover the much more interesting and important topic of using modules to hidebindings and types.Modules for Namespace ManagementTo learn the basics of ML, pattern-matching, and functional programming, we have written small programsthat are just a sequence of bindings. For larger programs, we want to use more structure in organizing ourcode. In ML, we can use structures to define modules that contain a collection of bindings. At its simplest,you can write structure Name = struct bindings end where Name is the name of your structure (youcan pick anything; capitalization is a convention) and bindings is any list of bindings, containing values,functions, exceptions, datatypes, and type synonyms. Inside the structure you can use earlier bindings justlike we have been doing “at top-level” (i.e., outside of any module). Outside the structure, you refer toa binding b in Name by writing Name.b. We have already been using this notation to use functions likeList.foldl; now you know how to define your own structures.Though we will not do so in our examples, you can nest structures inside other structures to create a tree-shaped hierarchy. But in ML, modules are not expressions: you cannot define them inside of functions, storethem in tuples, pass them as arguments, etc.Used like this, structures are providing just namespace management, a way to avoid different bindingsin different parts of the program from shadowing each other. Java packages provide similar support fornamespace management. Namespace management is very useful, but not very interesting. Much moreinteresting is giving structures signatures, which are types for modules. They let us provide strict interfacesthat code outside the module must obey. ML has several ways to do this with subtly different syntax andsemantics; we just show one way to write down an explicit signature for a module. Here is an examplesignature definition and structure definition that says the structure MyMathLib must have the signatureMATHLIB:signature MATHLIB =sigval fact : int -> intval half_pi : realval doubler : int -> intendstructure MyMathLib :> MATHLIB =structfun fact x =if x=0then 1else x * fact (x - 1)val half_pi = Math.pi / 2.0fun doubler y = y + yend1Because of the :> MATHLIB, the structure MyMathLib will typecheck only if it actually provides everything thesignature MATHLIB claims it does and with the right types. Signatures can also contain datatype, exception,and type bindings. Because we check the signature when we compile MyMathLib, we can use this informationwhen we check any code that uses MyMathLib. In other words, we can just check clients assuming that thesignature is correct.open: an overused by convenient shortcutIf in some scope you are using many bindings from another structure, it can be inconvenient to writeSomeLongStructureName.foo many times. Of course, you can use a val-binding to avoid this, e.g.,val foo = SomeLongStructureName.foo, but this technique is ineffective if we are using many differentbindings from the structure (we would need a new variable for each) or for using constructor names from thestructure in patterns. So ML allows you to write open SomeLongStructureName, which provides “direct”access (you can just write foo) to any bindings in the module that are mentioned in the module’s signature.The scope of an open is the rest of the enclosing structure (or the rest of the program at top-level).A common use of open is to write succinct testing code for a module outside the module itself. Other usesof open are often frowned upon because it may introduce unexpected shadowing, especially since differentmodules may reuse binding names. For example, a list module and a tree module may both have functionsnamed map.Hiding thingsBefore learning how to use ML modules to hide implementation details from clients, let’s remember thatseparating an interface from an implementation is probably the most important strategy for building correct,robust, reusable programs. Moreover, we can already use functions to hide implementations in various ways.For example, all 3 of these functions double their argument, and clients (i.e., callers) would have no way totell if we replaced one of the functions with a different one:fun double1 x = x + xfun double2 x = x * 2val y = 2fun double3 x = x * yAnother feature we use for hiding implementations is defining functions locally inside other functions. Wecan later change, remove, or add locally defined functions knowing the old versions were not relied on by anyother code. From an engineering perspective, this is a crucial separation of concerns. I can work on improvingthe implementation of a function and know that I am not breaking any clients. Conversely, nothing clientscan do can break how the functions above work.But what if you wanted to have two top-level functions that code in other modules could use and have bothof them use the same hidden functions? There are ways to do this (e.g., create a record of functions), but itwould be convenient to have some top-level functions that were “private” to the module. In ML, there is no“private” keyword like in other languages. Instead, you use signatures that simply mention less: anythingnot explicitly in a signature cannot be used from the outside. For example, if we change the signature aboveto:signature MATHLIB =sigval fact : int -> intval half_pi : realendthen client code cannot call MyMathLib.doubler. The binding simply is not in scope, so no use of it will2type-check. In general, the idea is that we can implement the module however we like and only bindingsthat are explicitly listed in the signature can be called directly by clients.Introducing our extended exampleThe rest of this lecture uses a small module that implements rational numbers. While a real library wouldprovide many more features, ours will just support creating fractions, adding two of them together, andconverting them to strings. Our library intends to (1) prevent denominators of zero and (2) keep fractionsin reduced form (3/2 instead of 9/6 and 4 instead of


View Full Document

UW CSE 341 - Lecture Notes

Documents in this Course
Macros

Macros

6 pages

Macros

Macros

6 pages

Macros

Macros

3 pages

Mutation

Mutation

10 pages

Macros

Macros

17 pages

Racket

Racket

25 pages

Scheme

Scheme

9 pages

Macros

Macros

6 pages

Load more
Download Lecture Notes
Our administrator received your request to download this document. We will send you the file to your email shortly.
Loading Unlocking...
Login

Join to view Lecture Notes and access 3M+ class-specific study document.

or
We will never post anything without your permission.
Don't have an account?
Sign Up

Join to view Lecture Notes 2 2 and access 3M+ class-specific study document.

or

By creating an account you agree to our Privacy Policy and Terms Of Use

Already a member?