OCamlDatatypesPartII:AnExerciseinTypeDesign
COS326DavidWalker
PrincetonUniversity
slidescopyright2017DavidWalkerpermissiongrantedtoreusetheseslidesfornon-commercialeducaJonalpurposes
1
ExampleTypeDesign 2
IBMdevelopedGML(GeneralizeMarkupLanguage)in1969• hSp://en.wikipedia.org/wiki/IBM_Generalized_Markup_Language• PrecursortoSGML,HTMLandXML
:h1.Chapter 1: Introduction :p.GML supported hierarchical containers, such as :ol :li.Ordered lists (like this one), :li.Unordered lists, and :li.Definition lists :eol. as well as simple structures. :p.Markup Minimization (later generalized and formalized in SGML), allowed the end-tags to be omitted for the “h1” and “p” elements.
SimplifiedGML 3
ToprocessaGMLdocument,anOCamlprogramwould:• Readaseriesofcharactersfromatextfile&ParseGMLstructure• RepresenttheinformaJoncontentasanOCamldatastructure• Analyzeortransformthedatastructure• Print/Store/CommunicateresultsWewillfocusonhowtorepresentandtransformtheinformaJoncontentofaGMLdocument.
ExampleTypeDesign 4
• AGMLdocumentconsistsof:– alistofelements
• Anelementiseither:– awordormarkupappliedtoanelement
• Markupiseither:– italicize,bold,orafontname
ExampleTypeDesign 5
type markup = Ital | Bold | Font of string type elt = Words of string list | Formatted of markup * elt type doc = elt list
• AGMLdocumentconsistsof:– alistofelements
• Anelementiseither:– awordormarkupappliedtoanelement
• Markupiseither:– italicize,bold,orafontname
ExampleData 6
type markup = Ital | Bold | Font of string type elt = Words of string list | Formatted of markup * elt type doc = elt list
let d = [ Formatted (Bold, Formatted (Font “Arial”,
Words [“Chapter”;“One”])); Words [“It”; ”was”; ”a”; ”dark”;
”&”; ”stormy; ”night.”; "A"];
Formatted (Ital, Words[“shot”]);
Words [“rang”; ”out.”] ];;
Challenge 7
• Changeallofthe“Arial”fontsinadocumentto“Courier”.• Ofcourse,whenweprogramfuncJonally,weimplement
changeviaafuncJonthat– receivesonedatastructureasinput– buildsanew(different)datastructureasanoutput
Challenge 8
• Changeallofthe“Arial”fontsinadocumentto“Courier”.
type markup = Ital | Bold | Font of string type elt = Words of string list | Formatted of markup * elt type doc = elt list
Challenge 9
• Changeallofthe“Arial”fontsinadocumentto“Courier”.
• Technique:approachtheproblemtopdown,workondocfirst:
let rec chfonts (elts:doc) : doc =
type markup = Ital | Bold | Font of string type elt = Words of string list | Formatted of markup * elt type doc = elt list
Challenge 10
• Changeallofthe“Arial”fontsinadocumentto“Courier”.
• Technique:approachtheproblemtopdown,workondocfirst:
let rec chfonts (elts:doc) : doc = match elts with | [] -> | hd::tl ->
type markup = Ital | Bold | Font of string type elt = Words of string list | Formatted of markup * elt type doc = elt list
Challenge 11
• Changeallofthe“Arial”fontsinadocumentto“Courier”.
• Technique:approachtheproblemtopdown,workondocfirst:
let rec chfonts (elts:doc) : doc = match elts with | [] -> [] | hd::tl -> (chfont hd)::(chfonts tl)
type markup = Ital | Bold | Font of string type elt = Words of string list | Formatted of markup * elt type doc = elt list
Changingfontsinanelement 12
• Changeallofthe“Arial”fontsinadocumentto“Courier”.
• Nextworkonchangingthefontofanelement:
let rec chfont (e:elt) : elt =
type markup = Ital | Bold | Font of string type elt = Words of string list | Formatted of markup * elt type doc = elt list
Changingfontsinanelement 13
• Changeallofthe“Arial”fontsinadocumentto“Courier”.
• Nextworkonchangingthefontofanelement:
let rec chfont (e:elt) : elt = match e with | Words ws -> | Formatted(m,e) ->
type markup = Ital | Bold | Font of string type elt = Words of string list | Formatted of markup * elt type doc = elt list
Changingfontsinanelement 14
• Changeallofthe“Arial”fontsinadocumentto“Courier”.
• Nextworkonchangingthefontofanelement:
let rec chfont (e:elt) : elt = match e with | Words ws -> Words ws | Formatted(m,e) ->
type markup = Ital | Bold | Font of string type elt = Words of string list | Formatted of markup * elt type doc = elt list
Changingfontsinanelement 15
• Changeallofthe“Arial”fontsinadocumentto“Courier”.
• Nextworkonchangingthefontofanelement:
let rec chfont (e:elt) : elt = match e with | Words ws -> Words ws | Formatted(m,e) -> Formatted(chmarkup m, chfont e)
type markup = Ital | Bold | Font of string type elt = Words of string list | Formatted of markup * elt type doc = elt list
Changingfontsinanelement 16
• Changeallofthe“Arial”fontsinadocumentto“Courier”.
• Nextworkonchangingamarkup:
let chmarkup (m:markup) : markup =
type markup = Ital | Bold | Font of string type elt = Words of string list | Formatted of markup * elt type doc = elt list
Changingfontsinanelement 17
• Changeallofthe“Arial”fontsinadocumentto“Courier”.
• Nextworkonchangingamarkup:
let chmarkup (m:markup) : markup = match m with | Font “Arial” -> Font “Courier” | _ -> m
type markup = Ital | Bold | Font of string type elt = Words of string list | Formatted of markup * elt type doc = elt list
Summary:Changingfontsinanelement 18
• Changeallofthe“Arial”fontsinadocumentto“Courier”• Lesson:funcJonstructurefollowstypestructure
let chmarkup (m:markup) : markup = match m with | Font “Arial” -> Font “Courier” | _ -> m let rec chfont (e:elt) : elt = match e with | Words ws -> Words ws | Formatted(m,e) -> Formatted(chmarkup m, chfont e) let rec chfonts (elts:doc) : doc = match elts with | [] -> [] | hd::tl -> (chfont hd)::(chfonts tl)
PoorStyle 19
• ConsideragainourdefiniJonofmarkupandmarkupchange:
type markup = Ital | Bold | Font of string let chmarkup (m:markup) : markup = match m with | Font “Arial” -> Font “Courier” | _ -> m
PoorStyle 20
• Whatifwemakeachange:
type markup = Ital | Bold | Font of string | TTFont of string let chmarkup (m:markup) : markup = match m with | Font “Arial” -> Font “Courier” | _ -> m
theunderscoresilentlycatchesallpossiblealternaJvesthismaynotbewhatwewant--perhapsthereisanArialTTfontitisbeSerifwearealertedofallfuncJonswhoseimplementaJonmayneedtochange
BeSerStyle 21
• Originalcode:
type markup = Ital | Bold | Font of string let chmarkup (m:markup) : markup = match m with | Font “Arial” -> Font “Courier” | Ital | Bold -> m
BeSerStyle 22
• Updatedcode:
type markup = Ital | Bold | Font of string | TTFont of string let chmarkup (m:markup) : markup = match m with | Font “Arial” -> Font “Courier” | Ital | Bold -> m
..match m with | Font "Arial" -> Font "Courier" | Ital | Bold -> m.. Warning 8: this pattern-matching is not exhaustive. Here is an example of a value that is not matched: TTFont _
BeSerStyle 23
• Updatedcode,fixed:
• Lesson:usethetypecheckerwherepossibletohelpyoumaintainyourcode
type markup = Ital | Bold | Font of string | TTFont of string let chmarkup (m:markup) : markup = match m with | Font "Arial" -> Font "Courier" | TTFont "Arial" -> TTFont "Courier" | Font s -> Font s | TTFont s -> TTFont s | Ital | Bold -> m
AcoupleofpracJceproblems 24
• WriteafuncJonthatgetsridofimmediatelyredundantmarkupinadocument.– FormaSed(Ital,FormaSed(Ital,e))canbesimplifiedtoFormaSed(Ital,e)
– writemapsandfoldsovermarkups• Designadatatypetodescribebibliographyentriesfor
publicaJons.SomepublicaJonsarejournalarJcles,othersarebooks,andothersareconferencepapers.Journalshaveaname,numberandissue;bookshaveanISBNnumber;AlloftheseentriesshouldhaveaJtleandauthor.– designasorJngfuncJon– designmapsandfoldsoveryourbibliographyentries
ToSummarize 25
• DesignrecipeforwriJngOCamlcode:– writedownEnglishspecificaJons
• trytobreakproblemintoobvioussub-problems– writedownsomesampletestcases– writedownthesignature(types)forthecode– usethesignaturetoguideconstrucJonofthecode:
• tearapartinputsusingpaSernmatching– makesuretocoverallofthecases!(OCamlwilltellyou)
• handleeachcase,buildingresultsusingdataconstructor– thisiswherehumanintelligencecomesintoplay– the“skeleton”givenbytypescanalmostbedoneautomaJcally!
• cleanupyourcode– useyoursampletests(andideallyothers)toensurecorrectness