46
Brutal [Meta]Introduction to Dependent Types in Agda February, 04 2013 00:00 — March, 14 2013 01:22 tags: fp (/note/tag/fp/) agda (/note/tag/agda/) dependent types (/note/tag/dependent types/) logic (/note/tag/logic/) Introduction to introduction Agda doesn’t lack tutorials and introductions, there is a whole page of them on the Agda wiki [1] (for a general documentation list see [2]). Personally, I recommend: Anton Setzer’s introduction (works especially very well for those with a logical background, but is easy enough to follow for everyone else too) [3] Ana Bove’s and Peter Dybjer’s introduction [4]. Ulf Norell’s introduction for functional programmers [5]. Thorsten Altenkirch’s lectures [6]. (This list is not an order, the best practice is to read them (and this page) simultaneously. By the way, this document is far from finished, but should be pretty useful in its current state.) Same proposition holds for Coq [7], Idris [8] and, to a lesser extent, for Epigram [9]. For a general introduction to type theory field look no further than: Morten Heine B. Sørensen’s and Pawel Urzyczyn’s lectures [10]. Simon Thompson’s book [11]. There’s also a number of theoretical books strongly related to the languages listed above: The notes of Per MartinLöf’s (the author of the core type theory used by all of Agda, Coq, Idris and Epigram) lectures [12], [13]. A bit more practicaloriented book by Bengt Nordström et al [14]. And a number of tutorials which show how to implement a dependently typed language yourself: “Simpler Easier” [15]. A tutorial by Andrej Bauer [16]–[18]. There’s a lot to read already, why another introduction? Because there is a gap. Theory is huge and full of subtle details that are mostly ignored in tutorial implementations and hidden in language tutorials (so that unprepared are not scared away). Which is hardly surprising since the current state of art takes years to implement correctly, and even then some (considerable) problems remain. Nevertheless, I think it is the hard parts that matter, and I always wanted a tutorial that at least mentioned their existence (well, obviously there is a set of dependently typed problems most people appreciate, e.g. undecidable type inference, but there is still a lot of issues that are not so wellunderstood). Moreover, about (/) activity (/activity/) notes (/note/)

Introduction to Dependent Types in Agda

  • Upload
    mks32

  • View
    37

  • Download
    3

Embed Size (px)

DESCRIPTION

Dependent Type theory

Citation preview

  • Brutal[Meta]IntroductiontoDependentTypesinAgdaFebruary,04201300:00March,14201301:22tags: fp(/note/tag/fp/) agda(/note/tag/agda/) dependenttypes(/note/tag/dependenttypes/) logic(/note/tag/logic/)

    IntroductiontointroductionAgdadoesnt lack tutorialsand introductions, there isawholepageof themon theAgdawiki [1] (forageneraldocumentationlistsee[2]).Personally,Irecommend:

    AntonSetzersintroduction(worksespeciallyverywellforthosewithalogicalbackground,butiseasyenoughtofollowforeveryoneelsetoo)[3]AnaBovesandPeterDybjersintroduction[4].UlfNorellsintroductionforfunctionalprogrammers[5].ThorstenAltenkirchslectures[6].

    (Thislistisnotanorder,thebestpracticeistoreadthem(andthispage)simultaneously.Bytheway,thisdocumentisfarfromfinished,butshouldbeprettyusefulinitscurrentstate.)

    SamepropositionholdsforCoq[7],Idris[8]and,toalesserextent,forEpigram[9].

    Forageneralintroductiontotypetheoryfieldlooknofurtherthan:

    MortenHeineB.SrensensandPawelUrzyczynslectures[10].SimonThompsonsbook[11].

    Theresalsoanumberoftheoreticalbooksstronglyrelatedtothelanguageslistedabove:

    ThenotesofPerMartinLfs(theauthorofthecoretypetheoryusedbyallofAgda,Coq,IdrisandEpigram)lectures[12],[13].AbitmorepracticalorientedbookbyBengtNordstrmetal[14].

    Andanumberoftutorialswhichshowhowtoimplementadependentlytypedlanguageyourself:

    SimplerEasier[15].AtutorialbyAndrejBauer[16][18].

    Theresalottoreadalready,whyanotherintroduction?Becausethereisagap.Theoryishugeandfullofsubtledetailsthataremostly ignoredintutorial implementationsandhiddeninlanguagetutorials(sothatunpreparedarenotscaredaway).Whichishardlysurprisingsincethecurrentstateofarttakesyearstoimplementcorrectly,andeventhensome(considerable)problemsremain.

    Nevertheless,Ithinkitisthehardpartsthatmatter,andIalwayswantedatutorialthatatleastmentionedtheir existence (well, obviously there is a set of dependently typed problemsmost people appreciate,e.g.undecidabletypeinference,butthereisstillalotofissuesthatarenotsowellunderstood).Moreover,

    about(/) activity(/activity/) notes(/note/)

  • after Istumbleduponsomeof these lesserknownpartsofdependently typedprogramming Istarted tosuspect thathiding thembehind the languagegoodnessesactuallymakes thingsharder to understand.DottedpatternsandunificationstuckerrorinAgdaareperfectexamples.Iclaimthat:

    Peoplefindithardtounderstanddottedpatternsexactlybecauseitshardtoexplainthemabovethelanguageabstractionlevel.Explicitaccesstounificationengineisausefulinteractiveprogramconstructiontool.IdidadozenofproofsIprobablycouldntdootherwisebyunifyingexpressionsbyhand.AsfarasImaware,noproofcheckerautomatesthisinausablewayyet.Thereisaproposal(http://code.google.com/p/agda/issues/detail?id=771)withmyimplementationideasfor agda2mode .

    Havingsaidthat,thisarticleservessomewhatcontroversialpurposes:

    ItisaintroductiontoAgda,startingasaverybasicone,writtenforthosewithhalfwaythroughundergradcourse(readbasic)discretemath,numbertheory,settheoryandHaskellbackground.Iactuallytaughtthistoundergradstudents[19]anditworks.ButitaimsnottoteachAgda,buttoshowhowdependentlytypedlanguagesworkbehindthesceneswithoutactuallygoingbehindthescenes(because,asnotedabove,goingbehindthescenestakesyears).ImprettysureitispossibletowriteaverysimilarintroductiontoCoq,Idris,Epigramorwhatever,butAgdaworksperfectlybecauseofitssyntaxandheavyunificationusage.Thereisalsoanumberof[italicizedcommentsinbrackets]layingaround,usuallyforthosewithtypetheorybackground.Dontbescared,youcancompletelyignorethem.Theygivedeeperinsightsifyouresearchonthem,though.Thelasttwosectionscontaincompletelytypetheoreticstuff.TheyarethereasonIstartedwritingthis,but,still,youmayignorethemcompletelyifyouwish.Youareexpectedtounderstandeverythingelse.Doexercisesandswitchtoothertutorialswhenstuck.

    Finally,beforewestart,adisclaimer:Iverifiedmycorethoughtsabouthowallthisstuffworksbyreading(partsof)Agdassourcecode,butstill,asPlatosSocratesstated,IknowthatIknownothing.

    SlowstartYouwanttouseEmacs,trustmeThereisagda2modeforEmacs.Itallowsto:

    inputfunnyUNICODEsymbolslikeor,interactivelyinteractwithAgda(moreonthatbelow).

    Installation:

    install emacs ,installeverythingwith agda substringfromyourpackagemanageror Agda and Agdaexecutablewith cabal ,run agdamodesetup .

    Running:

    run emacs ,press CxCfFileNameRET (Control+x,Control+f,typeFileName,pressReturn/Enterkey).

  • Notethatyoucanloadthisarticle inLiterateAgdaformat(../BrutalDepTypes.lagda)directly intoEmacs.Thisisactuallyarecommendedwaytousethistext,youcantdoexercisesinHTMLversion.

    SyntaxInAgdaamoduledefinitionalwaysgoesfirst:

    moduleBrutalDepTypeswhere

    Nestedmodulesandmoduleswithparametersaresupported.Oneofthemostcommonusagesofnestedmodulesistohidesomedefinitionsfromthetoplevelnamespace:

    moduleThrowAwayIntroductionwhere

    DatatypesarewritteninGADTsstyle:

    dataBool:Setwheretruefalse:BoolNote,wecanlistconstructorsofasametypebyinterspersingthemwithspaces.

    inputforis\bn,inputforis\to,but>isfinetooNaturals.data:Setwherezero:succ:

    IdentitycontainerdataId(A:Set):Setwherepack:AIdA

    inputforis\botEmptytype.Absurd.Falseproposition.data:Setwhere

    Set heremeansthesamethingaskind * inHaskell,i.e.atypeoftypes(moreonthatbelow).

    Agdaisatotallanguage.Thereisno undefined ,allfunctionsareguaranteedtoterminateonallpossibleinputs(ifnotexplicitlystatedotherwisebyacompilerflagorafunctiondefinitionitself),whichmeansthat typeisreallyempty.

    FunctiondeclarationsareverymuchlikeinHaskell:

    inputforis\_0,is\_1andsoonid:idx=x

    exceptfunctionargumentshavetheirnamesevenintypeexpressions:

  • Note,argument'snameinatypemightdifferfromanameusedinpatternmatchingid:(n:)idx=xthis`x`referstothesameargumentas`n`inthetype

    with id sdefinitionbeingasyntaxsugarfor:

    id:(_:)idx=x

    wheretheunderscoremeansIdontcareaboutthename,justlikeinHaskell.

    Dependenttypesallowtypeexpressionsafteranarrowtodependonexpressionsbeforethearrow,thisisusedtotypepolymorphicfunctions:

    id:(A:Set)AAid_a=a

    Notethatthistime A inthetypecannotbechangedintoanunderscore,butitsfinetoignorethisnameinpatternmatching.

    Patternmatchinglooksasusual:

    not:BoolBoolnottrue=falsenotfalse=true

    exceptifyoumakeanerrorinaconstructorname:

    not:BoolBoolnottrue=falsenotfals=true

    Agdawillsaynothing.Thismightbecriticalsometimes:

    dataThree:SetwhereCOneCTwoCThree:Three

    three2:Threethree2COne=zerothree2Ctwo=succzerothree2_=succ(succzero)intersectswiththepreviousclause

    Finally,Agdasupportsimplicitarguments:

    id:{A:Set}AAida=a

    idTest:idTest=id

    Valuesofimplicitargumentsarederivedfromotherargumentsvaluesandtypesbysolvingtypeequations

  • (moreonthembelow).Youdonthavetoapplythemorpatternmatchonthemexplicitly,butyoustillcanifyouwish:

    positional:id:{A:Set}AAid{A}a=a

    idTest:idTest=id{}

    named:const:{A:Set}{B:Set}ABAconst{B=_}a_=a

    constTest:constTest=const{A=}{B=}

    [Its important tonotethatnoproofsearch iseverdone.Implicitargumentsarecompletelyorthogonal tocomputational aspect of a program, being implicit doesnt imply anythingelse. Implicit variables are nottreatedanywayspecial,theyarenottypeerasedanywaydifferentlythanothers.Theyarejustakindofsyntaxsugarassistedbyequationsolving.]

    Itsallowedtoskiparrowsbetweenargumentsinparenthesesorbraces:

    id:{A:Set}(a:A)Aida=a

    andtointerspersenamesofvaluesofthesametypebyspacesinsideparenthesesandbraces:

    const:{AB:Set}ABAconsta_=a

    WhatmakesAgdassyntaxsoconfusingistheusageofunderscore.InHaskellIdontcareaboutthenameistheonlymeaningforit,inAgdathereareanothertwoandahalf.Thefirstonebeingguessthevalueyourself:

    idTest:idTest=id_

    whichworksexactlythesamewayasimplicitarguments.

    Or, to be more precise, it is the implicit arguments that work like arguments implicitly applied withunderscores,exceptAgdadoesthisonceforeachfunctiondefinition,notforeachcall.

    Theanotherhalfbeingguessthetypeyourself:

    unpack:{A:_}IdAAunpack(packa)=a

    whichhasaspecial syntaxsugar:

  • inputforis\allor\forallunpack:{A}IdAAunpack(packa)=a

    explicitargumentversion:unpack:AIdAAunpack_(packa)=a

    extendstotherightuptothefirstarrow:

    unpack:{AB}IdAIdBAunpack(packa)_=a

    unpack:{A}(_:IdA){B}IdBAunpack(packa)_=a

    Datatypesyntaxassumesimplicit whenthereisnotypespecified:

    dataForAllIdA(B:IdA):Setwhere

    ItisimportanttonotethatAgdas isquitedifferentfromHaskells ( forall ).Whenwesay n inAgda its perfectly normal for n: to be inferred, but inHaskell n alwaysmeans {n : Set} ,[i.e.Haskells isanimplicit(HindleyMilner)versionofsecondorderuniversalquantifierwhileinAgdaitsjustasyntaxsugar].

    Syntaxmisinterpretingbecomesahugeproblemwhenworkingwithmorethanoneuniverselevel(moreonthat below). It is important to train yourself to desugar type expressions subconsciously (by doing inconsciously at first). It will save hours of your time later. For instance, {A} Id A A means{A:_}(_:IdA)A (wherethelast A shouldbeinterpretedas (_:A) ),i.e.thefirst A isavariablename,whiletheotherexpressionsaretypes.

    Finally,thelastmeaningofanunderscoreistomarkargumentsplacesinfunctionnamesforthe MixFixparser,i.e.anunderscoreinafunctionnamemarkstheplacewheretheargumentsgoes:

  • if_then_else_:{A:Set}BoolAAAiftruethenaelse_=aiffalsethen_elseb=b

    Aretwosequal?_=?_:Boolzero=?zero=truezero=?succm=falsesuccm=?zero=falsesuccn=?succm=n=?m

    Sumfor.infix6_+__+_:zero+n=nsuccn+m=succ(n+m)

    ifthenelseTest:ifthenelseTest=if(zero+succzero)=?zerothenzeroelsesucc(succzero)

    ListsdataList(A:Set):Setwhere[]:ListA__:AListAListA

    [_]:{A:Set}AListA[a]=a[]

    listTest:ListlistTest=[]

    listTest:ListlistTest=zero(zero(succzero[]))

    Notethefixitydeclaration infix whichhasthesamemeaningasinHaskell.Wedidntwrite infixl forareason.WithdeclaredassociativityAgdawouldnotprintredundantparentheses,whichisgoodingeneral,butwouldsomewhatcomplicateexplanationofaseveralthingsbelow.

    Thereisa where construct,justlikeinHaskell:

  • ifthenelseTest:ifthenelseTest=if(zero+succzero)=?zerothenzeroelsexwherex=succ(succzero)

    Whilepatternmatching,thereisaspecialcasewhenatypewearetryingtopatternmatchonisobviously([typeinhabitanceproblemisundecidableinageneralcase])empty.Thisspecialcaseiscalledanabsurdpattern:

    impliesanything.elim:{A:Set}Aelim()

    whichallowsyoutoskiparighthandsideofadefinition.

    Youcanbindvariableslikethatstill:

    Absurdimpliesanything,taketwo.elim:{A:Set}Aelimx=elimx

    Agdahasrecords,whichworkverymuch like newtype declarations inHaskell, i.e. theyaredatatypeswithasingleconstructorthatisnotstored.

    recordPair(AB:Set):Setwherefieldfirst:Asecond:B

    getFirst:{AB}PairABAgetFirst=Pair.first

    Note, however, that toprevent nameclashes recorddefinitiongeneratesamodulewith fieldextractorsinside.

    Thereisaconventiontodefineatypewithoneelementasarecordwithnofields:

    inputforis\topOneelementtype.Recordwithoutfields.Trueproposition.record:Setwhere

    tt:tt=record{}

    Aspecialthingaboutthisconventionisthatanargumentofanemptyrecordtypeautomaticallygetsthevalue record{} whenappliedimplicitlyorwithunderscore.

    Lastly,Agdausesoversimplifiedlexerthatsplitstokensbyspaces,parentheses,andbraces.Forinstance

  • (notethenameofthevariablebinding):

    inputforis\`inputforis\'elim:{A:Set}Aelimx:=elimx:

    istotallyfine.Alsonotethat doesntgenerateacommenthere.

    ThemagicofdependenttypesLetsdefinethedivisionbytwo:

    div2:div2zero=zerodiv2(succ(succn))=succ(div2n)

    theproblemwiththisdefinitionisthatAgdaistotalandwehavetoextendthisfunctionforoddnumbers

    div2(succzero)={!checkme!}

    bychanging {!checkme!} intosometerm,mostcommonchoicebeing zero .

    Supposenow,weknowthatinputsto div2 arealwaysevenandwedontwanttoextend div2 forthesucczero case.Howdoweconstrain div2 toevennaturalsonly?Withapredicate!Thatis, evenpredicate:

    even:Setevenzero=even(succzero)=even(succ(succn))=evenn

    whichreturns withwithatrivialproof tt whenargumentisevenandempty thentheargumentisodd.

    Nowthedefinitionof div2e constrainedtoevennaturalsonlybecomes:

    div2e:(n:)evennNote,wehavetogiveaname`n`tothefirstargumentherediv2ezerop=zerodiv2e(succzero)()div2e(succ(succy))p=succ(div2eyp)Note,aproofof`even(succ(succn))`translatestoaproofof`evenn`bythedefinitionof`even`.

    Whenprogrammingwithdependent types,apredicateon A becomesa function from A to types, i.e.ASet . If a:A satisfiesthepredicate P:ASet thenthefunction P returnsatypewitheachelementbeingaproofof Pa ,inacase a doesntsatisfy P itreturnsanemptytype.

    Themagicofdependenttypesmakesthetypeofthesecondargumentof div2e changeeverytimewe

  • patternmatchonthefirstargument n .Fromthecalleeside,ifthefirstargumentisoddthenthesecondargumentwouldget typesometime(afteranumberofrecursivecalls)enablingtheuseofanabsurdpattern.Fromthecallerside,wearenotabletocallthefunctionwithanodd n ,sincewehavenomeanstoconstructavalueforthesecondargumentinthiscase.

    TypefamiliesandUnificationThereisanotherwaytodefineevenpredicate.Thistimewithadatatypeindexedby:

    dataEven:Setwhereezero:Evenzeroe2succ:{n:}EvennEven(succ(succn))

    twoIsEven:Even(succ(succzero))twoIsEven=e2succezero

    Even:Set isafamilyoftypesindexedbyandobeyingthefollowingrules:

    Evenzero hasoneelement ezero .Foranygiven n type Even(succ(succn)) hasoneelementif Evenn isnonempty.Therearenootherelements.

    Comparethisto even:Set definitiontranslation:

    Thereisatrivialproofthat zero hasproperty even .Thereisnoproofthat succzero hasproperty even .If n hasproperty even thensohas succ(succn) .

    In otherwords, thedifference is that Even : Set constructs a typewhereas even : Setreturnsatypewhenappliedtoanelementof .

    Theproofthattwoiseven even(succ(succzero)) literallysaystwoisevenbecauseithasatrivialproof,whereastheproofthattwoiseven twoIsEven saystwoisevenbecausezeroisevenandtwoisthesuccessorofthesuccessorofzero.

    Even datatypeallowsustodefineanothernonextendeddivisionbytwofor :

    div2E:(n:)Evenndiv2Ezeroezero=zerodiv2E(succzero)()div2E(succ(succn))(e2succstilleven)=succ(div2Enstilleven)Comparethiscasetodiv2e.

    Note,thereisnocasefor div2Ezero(e2succx) since e2succx hasthewrongtype,thereisnosuchconstructor in Evenzero .For the succzero case the typeof thesecondargument isnot ,but isempty.Howdoweknowthat?Unification!

    Unificationisthemostimportant(atleastwithpatternmatchingoninductivedatatypesinvolved)andeasilyforgottenaspectofdependentlytypedprogramming.Giventwoterms M and N unificationtriestofindasubstitution s suchthatusing s on M givesthesameresultasusing s on N .Theprecisealgorithmdefinitionisprettylong,buttheideaissimple:todecideiftwoexpressionscouldbeunifiedwe

  • reducethemasmuchaspossible,thentraversetheirspinesuntilwe

    hitanobviousdifferencebetweenthem,findaplacewherewecannotdecideforsure,orsuccessfullyfinishthetraversalgeneratingasubstitution s .

    Forinstance:

    Tounify[ (succa)+b with succ(c+d) ]weneedreducebothofthem,nowweneedtounify[ succ(a+b) with succ(c+d) ],whichmeansthatweneedtounify[ a+b with c+d ],whichmeansthatweneedtounify[ a with c ]and[ b with d ],whichmeansthat[ a=c , b=d ].Ontheotherhand, succa cannotbeunifiedwith zero forany a ,and succb cannotbeunifiedwith b forany b .Wedontknowifitspossibletounify foon with zero forsomeunknownfunction foo (itmightormightnotreduceto zero forsome n ).

    In the code above succ zero doesnt unify with any of the Even constructors indexes [ zero ,succ(succn) ]whichmakesthistypeobviouslyemptybyitsdefinition.

    [RefertoTheviewfromtheleftpaperbyMcBrideandMcKinna[20]formoredetailsonpatternmatchingwithtypefamilies.]

    MoretypefamiliesandlessUnificationIndatatypedeclarationsthingsbeforea : arecalledparameters,thingsafterthecolonbutbeforea Setarecalledindexes.

    Thereisafamousdatatypeinvolvingbothofthem:

    dataVec(A:Set):Setwhere[]:VecAzero__:{n}AVecAnVecA(succn)

    VecAn isavectorofvaluesoftype A andlength n , Vec hasaparameteroftype Set andisindexedbyvaluesoftype .Comparethisdefinitionto thedefinitionof List and Even .Notealso, thatAgdatoleratesdifferentdatatypeswithconstructorsofthesamename(seebelowforhowthisisresolved).

    Wecannotomittheclauseforan [] caseinafunctionwhichtakesaheadofa List :

    head:{A}ListAAhead[]={!checkme!}head(aas)=a

    butwehavenothingtowriteinplaceof {!checkme!} there(ifwewanttobetotal).

    Ontheotherhand,thereisno [] constructorina VecA(succn) type:

    head:{An}VecA(succn)Ahead(aas)=a

  • Notethattherearenoabsurdpatternshere, VecA(succn) isinhabited,itjusthappensthatthereisno[] inthere.

    Bytheway,the Vec typeisfamousforaconcatenationfunction:

    Concatenationfor`List`s_++_:{A}ListAListAListA[]++bs=bs(aas)++bs=a(as++bs)

    Concatenationfor`Vec`torsThelengthofaconcatenationisthesumoflengthsofargumentsandisavailableintypes._++v_:{Anm}VecAnVecAmVecA(n+m)[]++vbs=bs(aas)++vbs=a(as++vbs)

    Compare _+_ , _++_ ,and _++v_ definitions.

    Whydoesthedefinitionof _++v_ work?Becausewedefined _+_ thisway!Inthefirstclauseof _++v_the typeof [] gives n=zero byunification, zero+m=m by the _+_ definition, bs:VecAm .Similarly,inthesecondclause n=succn0 , as:VecAn0 , (succn0)+m=succ(n0+m) bythe_+_ definition, a(as++bs):succ(n0+m) .

    DottedpatternsandUnificationLetsdefineasubstraction:

    infix6____:zero_=zerosuccnzero=succnsuccnsuccm=nm

    Notethat nm=zero for m>n .

    Letusgetridofthis (succn)zero casewith __ relation:

    data__:Setwherezn:{n}zeronss:{nm}nmsuccnsuccm

    Wearenowabletowriteasubstractionthatisnotextendedfor m>n .

    sub:(nm:)mnsubnzero(zn.{n})=nsub.(succn).(succm)(ss{m}{n}y)=subnmy

    Notethedots,thesearecalleddottedpatterns.Ignorethemforasecond.

  • Consider thecase subnzero(zn{k}) .The typeof the thirdargument is zeron .The typeofzn{k} is zerok .Unificationofthesetwotypesgives[ k=n , m=zero ].Afterasubstitutionweget subnzero(zn{n}) .Whichofthe n swewanttobind/matchon?Inthecodeabovewesayonthefirstandplaceadotbeforethesecondoccurrencetomarkthisintention.Dottedpatternsaysdonotmatchonthis,itistheonlypossiblevaluetothecompiler.

    Thesecondclauseis subnm(ss{n'}{m'}y) .Thetypeofthethirdargumentis mn .Thetypeofss{n'}{m'}y is succn'succm' .Thisgives[ n=succn' , m=succm' ].Thistimewedecidedtomatchon n' and m' .

    Rewrittenwitha case constructfromHaskell(Agdadoesnthave case ,seebelow)thecodeabovebecomes(inpseudoHaskell):

    subnmeven=caseevenofzn{k}>casemof[`k=n`,`m=zero`]zero>nsuccm'>__IMPOSSIBLE__since`m=zero`doesn'tmergewith`m=succm'`ssn'm'y>subn'm'y[`n=succn'`,`m=succn'`]

    Where __IMPOSSIBLE__ isjustlikean undefined butisneverexecuted.

    Note,thatwehave[ k=n , m=zero ]inthefirstcaseforeven.Thismeanswecandotthefirstusageofzero tooptimizethematchon m away:

    sub:(nm:)mnsubn.zero(zn.{n})=nsub.(succn).(succm)(ss{m}{n}y)=subnmy

    whichtranslatesto

    subnmeven=caseevenofzn{k}>nssn'm'y>subn'm'y

    Finally,wecanalsorewrite sub tomatchonthefirsttwoarguments(usual,commonsensedefinition):

    sub:(nm:)mnsubnzero(zn.{n})=nsub(succn)(succm)(ss.{m}.{n}y)=subnmy

    whichtranslatesintothefollowing:

  • subnmeven=casemofzero>caseevenofzn{k}>nss{k}{l}y>__IMPOSSIBLE__since`zero`(`m`)can'tbeunifiedwith`succk`succm'>casenofzero>caseevenofzn{k}>__IMPOSSIBLE__since`succm'`(`m`)can'tbeunifiedwith`zero`ss{k}{l}y>__IMPOSSIBLE__since`zero`(`n`)can'tbeunifiedwith`succl`succn'>caseevenofzn{k}>__IMPOSSIBLE__since`succn'`(`n`)can'tbeunifiedwith`zero`ss{k}{l}y>subn'm'y

    Exercise.WriteouttheunificationconstraintsforthepseudoHaskelltranslationabove.

    Note,that subnmp computesthedifferencebetween n and m while sub and sub extractitfromtheproof p .Notealso,thatfor subnzero thethirdargumentisalways zn{n} ,sowewouldliketowrite

    sub:(nm:)mnsubnzero.(zn{n})=nsub(succn)(succm)(ss.{m}.{n}y)=subnmy

    butAgdadoesntallowthis.Seebelowforwhy.

    Wecanwrite

    sub:(nm:)mnsubnzero_=nsub(succn)(succm)(ss.{m}.{n}y)=subnmy

    still.

    Exercise.TranslatethefollowingdefinitionintopseudoHaskellwithunificationconstraints:

    sub:(nm:)mnsubnzero(zn.{n})=nsub(succ.n)(succ.m)(ss{m}{n}y)=subnmy

    The moral is that dotted patterns are inlined unification constraints. This is why we couldnt dotzn{n} inthefirstclauseof sub ,Agdadidntgeneratesuchaconstraint (itcould,have it triedabitharder).

    PropositionalequalityandUnificationWeshallnowdefinethemostusefultypefamily,thatis,MartinLfsequivalence(valuesonlyversion,though):

  • is\==infix4__data__{A:Set}(x:A):ASetwhererefl:xx

    For xy:A thetype xy hasexactlyoneconstructor refl if x and y areconvertible, i.e. thereexistsuch z that zx and z y , where is reduces in zero ormore steps. By aconsequence from a ChurchRosser theorem and strong normalization convertibility can be solved bynormalization.Whichmeans thatunificationwillbothcheckconvertibilityand fill inanymissingparts. Inotherwords, xy:A thetype xy hasexactlyoneconstructor refl if x and y unifywitheachother.

    Letsprovesomeof __ sproperties:

    __issymmetricsym:{A:Set}{ab:A}abbasymrefl=refl

    transitivetrans:{A:Set}{abc:A}abbcactransreflrefl=refl

    andcongruentcong:{AB:Set}{ab:A}(f:AB)abfafbcongfrefl=refl

    Considerthecase sym{A}{a}{b}(refl{x=a}) .Matchingon refl gives[ b=a ]equation,i.e.theclauseactuallyis sym{A}{a}.{a}(refl{x=a}) whichallowstowrite refl ontherighthandside.Otherproofsaresimilar.

    Note,wecanprove sym theotherway:

    sym:{A:Set}{ab:A}abbasym{A}.{b}{b}refl=refl

    sym packs a into refl . sym packs b . Are these two definitions equal? is an interestingphilosophicalquestion.(FromtheAgdaspointofviewtheyare.)

    Sincedottedpatternsare justunificationconstraints,youdonthavetodot implicitargumentswhenyoudontbindormatchonthem.

    __ type family is called propositional equality. In Agdas standard library it has a bit more generaldefinition,seebelow.

    ProvingthingsinteractivelyWith __ wecanfinallyprovesomethingfrombasicnumbertheory.Letsdothisinteractively.

    Ourfirstvictimistheassociativityof _+_ .

  • +assoc:abc(a+b)+ca+(b+c)+assocabc={!!}

    Noteamark {!!} .Anythingoftheform {!expr!} with expr beinganystring(includingempty)agoalafterabuffer is loadedbyagda2mode.Typing {!!} isquite tedious,so there isashortcut ? .All ?symbolsareautomaticallytransformedinto {!!} whenabufferisloaded.

    Goalsappearasgreenholes inabuffer,pressingspecialkeysequenceswhile inagoalallows toaskAgdaquestionsaboutandperformactionsonacode.Inthisdocumentcheckmeinagoalmeansthatthisgoalisnotexpectedtobefilled,itsjustanexample.

    Press CcCl (load)toloadandtypecheckthebuffer.

    Placingthecursorinthegoalabove(thegreenholeinthetext)andpressing CcCcaRET (caseby a )gives(ignorechangestothenameofafunctionandcheckmeseverywhere):

    +assoc:abc(a+b)+ca+(b+c)+assoczerobc={!checkme!}+assoc(succa)bc={!checkme!}

    Press CcC, (goaltypeandcontext)whileinthegoal.Thiswillshowthegoaltypeandthecontextinsidethehole.Write refl inthereandpress CcCr (refine),thisgives:

    +assoc:abc(a+b)+ca+(b+c)+assoczerobc=refl+assoc(succa)bc={!checkme!}

    CcCf (nextgoal),write congsucc there, CcCr :

    +assoc:abc(a+b)+ca+(b+c)+assoczerobc=refl+assoc(succa)bc=congsucc{!checkme!}

    Nextgoal,goaltypeandcontext,press CcCa (autoproofsearch):

    +assoc:abc(a+b)+ca+(b+c)+assoczerobc=refl+assoc(succa)bc=congsucc(+assocabc)

    Done.

    (InAgda2.3.2youhavetoreloadabufferforproofsearchtowork,itsprobablyabug.)

    Similarly,weprove

  • lemma+zero:aa+zeroalemma+zerozero=refllemma+zero(succa)=congsucc(lemma+zeroa)

    lemma+succ:absucca+ba+succblemma+succzerob=refllemma+succ(succa)b=congsucc(lemma+succab)

    Thecommutativityfor _+_ isnothardtofollowtoo:

    Afunwaytowritetransitivityinfixr5_~__~_=trans

    +comm:aba+bb+a+commzerob=sym(lemma+zerob)+comm(succa)b=congsucc(+commab)~lemma+succba

    Nicewaytostepthroughaproofistowrapsomesubexpressionwith {!!} ,e.g.:

    +comm(succa)b=congsucc{!(+commab)!}~lemma+succba

    andaskforatype,contextandinferredtypeofagoalwith CcCl followedby CcC. ,refine,wrapanothersubexpression,repeat.Idreamofabetterinterfaceforthis.

    SolvingtypeequationsThe second case of +comm is pretty fun example to infer implicit arguments by hand. Lets do that.Algorithmisasfollows:

    First,expandallimplicitargumentsandexplicitargumentsappliedwith _ inatermintometavariables,thatis,specialmetalevelvariablesnotboundanywhereintheprogram.Lookatthetypesofallsymbolsandconstructasystemofequations.Forinstance,ifyouseeterm1term2:D , term1:AB and term2:C ,addequations A==C and B==D tothesystem.Solvethesystemwithahelpfromunification.Twopossibleresults:

    Allthemetavariablesgottheirvaluesfromthesolution.Success.Therearesomethatdidnt.Thissituationisreportedtoauserasunsolvedmetastypecheckingresult.Theseactlikewarningswhileyouarenottryingtocompileortotypecheckinasafemode.Inthelattertwocasesunsolvedmetastransformintoerrors.

    Substitutethevaluesofmetavariablesbackintotheterm.

    Applyingthefirststepofthealgorithmtoaterm

    trans(congsucc(+comm1ab))(lemma+succba)

    gives:

    trans{ma}{mb}{mc}{md}(cong{me}{mf}{mg}{mh}succ(+commab))(lemma+succba)

  • with m* beingmetavariables.

    ab: since _+_: inthetypeof +comm .Thisgivesthefollowingsystem(withduplicatedequationsandmetavariableapplicationsskipped):

    trans(congsucc(+commab))(lemma+succba):__{}(succa+b)(b+succa)trans(congsucc(+commab))(lemma+succba):__{}(succ(a+b))(b+succa)afternormalizationma=mb=succ(a+b)md=b+succa+commab:__{}(a+b)(b+a)mg=(a+b)me=mh=(b+a)mf=congsucc(+commab):__{}(succ(a+b))(succ(b+a))mc=succ(b+a)lemma+succba:__{}(succb+a)(b+succa)lemma+succba:__{}(succ(b+a))(b+succa)afternormalizationtrans(congsucc(+commab))(lemma+succba):__{}(succa+b)(b+succa)

    ThemostawesomethingaboutthisisthatfromAgdaspointofview,agoalisjustametavariableofaspecialkind.Whenyouaskforatypeofagoalwith CcCt or CcC, Agdaprintseverythingithasforthecorrespondingmetavariable.Funnythingslike ?0 , ?1 ,andetcinagda2modeoutputsarereferencestothesemetavariables.Forinstance,inthefollowing:

    metaVarTest:Vec(div2(succzero))metaVarTest={!checkme!}

    thetypeofthegoalmentionsthenameofveryfirstgoalmetavariablefromthisarticle.

    By the way, to resolve datatype constructor overloading Agda infers the type for a constructor callexpectedat the call site, andunifies the inferred typewith the typesof all possible constructorsof thesamename. If therearenomatches found,anerror is reported. Incasewithmore thanonealternativeavailable,anunsolvedmeta(forthereturntypemetavariable)isproduced.

    Terminationchecking,wellfoundedinductionWorkinprogress.

    PropositionalequalityexercisesExercise.Definemultiplicationbyinductiononthefirstargument:

    moduleExercisewhereinfix7_*__*_:n*m={!!}

  • sothatthefollowingproofworks:

    Distributivity.*+dist:abc(a+b)*ca*c+b*c*+distzerobc=reflis\lambda*+dist(succa)bc=cong(xc+x)(*+distabc)~sym(+assocc(a*c)(b*c))

    Now,fillinthefollowinggoals:

    *assoc:abc(a*b)*ca*(b*c)*assoczerobc=refl*assoc(succa)bc=*+distb(a*b)c~cong{!!}(*assocabc)

    lemma*zero:aa*zerozerolemma*zeroa={!!}

    lemma+swap:abca+(b+c)b+(a+c)lemma+swapabc=sym(+assocabc)~{!!}~+assocbac

    lemma*succ:aba+a*ba*succblemma*succab={!!}

    *comm:aba*bb*a*commab={!!}

    Pressing CcC. whilethereisaterminaholeshowsagoaltype,contextandthetermsinferredtype.Incrediblyusefulkeysequenceforinteractiveproofediting.

    Patternmatchingwith withConsiderthefollowingimplementationofa filter functioninHaskell:

    filter::(aBool)[a][a]filterp[]=[]filterp(a:as)=casepaofTrue>a:(filterpas)False>filterpas

    ItcouldberewrittenintoAgdalikethis:

    filter:{A:Set}(ABool)ListAListAfilterp[]=[]filterp(aas)withpa...|true=a(filterpas)...|false=filterpas

    whichdoesntlookverydifferent.Butdesugaring ... bytherulesofAgdasyntaxmakesitabitless

  • similar:

    filter:{A:Set}(ABool)ListAListAfilterp[]=[]filterp(aas)withpafilterp(aas)|true=a(filterpas)filterp(aas)|false=filterpas

    Theresnodirectanalogueto case inAgda, with constructionallowspatternmatchingonintermediateexpressions(justlikeHaskells case ),but(unlike case )onatoplevelonly.Thus with effectively justaddsaderivedargumenttoafunction.Just likewithnormalarguments,patternmatchingonaderivedargumentmightchangesometypesinacontext.

    The top level restrictionsimplifiesall thedependently typedstuff (mainly related todottedpatterns),butmakessomethingsalittlebitmoreawkward(inmostcasesyoucanemulate case withasubtermplacedintoa where block).Syntactically,verticalbarsseparatenormalarguments fromaderivedonesandaderivedonesfromeachother.

    Obfuscatingthefunctionabovegives:

    filterN:{A:Set}(ABool)ListAListAfilterNp[]=[]filterNp(aas)withpafilterNp(aas)|truewithasfilterNp(aas)|true|[]=a[]filterNp(aas)|true|bbswithpbfilterNp(aas)|true|bbs|true=a(bfilterNpbs)filterNp(aas)|true|bbs|false=afilterNpbsfilterNp(aas)|false=filterNpasoralternativelyfilterP:{A:Set}(ABool)ListAListAfilterPp[]=[]filterPp(a[])withpafilterPp(a[])|true=a[]filterPp(a[])|false=[]filterPp(a(bbs))withpa|pbfilterPp(a(bbs))|true|true=a(bfilterPpbs)filterPp(a(bbs))|true|false=afilterPpbsfilterPp(a(bbs))|false|true=bfilterPpbsfilterPp(a(bbs))|false|false=filterPpbs

    whichshowsthat with couldbenestedandmultiplematchesareallowedtobedoneinparallel.

    Letusprovethatallthesefunctionsproduceequalresultswhenappliedtoequalarguments:

    filterfilterN:{A:Set}(p:ABool)(as:ListA)filterpasfilterNpasfilterfilterNp[]=reflfilterfilterNp(aas)={!checkme!}

  • notethegoaltype (filterp(aas)|pa)(filterNp(aas)|pa) whichshows pa asderivedargumentto filter function.

    Rememberthattoreduce a+b wehadtomatchon a intheproofsabove,matchingon b gavenothinginterestingbecause _+_ wasdefinedbyinductiononthefirstargument.Similarly,tofinishthefilterfilterN proofwehavetomatchon pa , as ,and pb ,essentiallyduplicatingtheformoffilterN term:

    filterfilterN:{A:Set}(p:ABool)(as:ListA)filterpasfilterNpasfilterfilterNp[]=reflfilterfilterNp(aas)withpafilterfilterNp(aas)|truewithasfilterfilterNp(aas)|true|[]=reflfilterfilterNp(aas)|true|bbswithpbfilterfilterNp(aas)|true|bbs|true=cong(xa(bx))(filterfilterNpbs)filterfilterNp(aas)|true|bbs|false=cong(__a)(filterfilterNpbs)filterfilterNp(aas)|false=filterfilterNpas

    Exercise.Guessthetypesfor filterfilterP and filterNfilterP .Arguewhichoftheseiseasiertoprove?Doit(andgettheotheronealmostforfreebytransitivity).

    Rewritingwith with andUnificationWhenplayingwiththeproofsaboutfiltersyoumighthadnoticedthat with doessomethinginterestingwithagoal.

    Inthefollowinghole

    filterfilterN:{A:Set}(p:ABool)(as:ListA)filterpasfilterNpasfilterfilterNp[]=reflfilterfilterNp(aas)={!checkme!}

    thetypeofthegoalis (filterp(aas)|pa)(filterNp(aas)|pa) .Butafterthefollowing with

    filterfilterN:{A:Set}(p:ABool)(as:ListA)filterpasfilterNpasfilterfilterNp[]=reflfilterfilterNp(aas)withpa|as...|r|rs={!checkme!}

    itbecomes (filterp(ars)|r)(filterNp(ars)|r) .

    Samethingsmighthappennotonlytoagoalbuttoacontextasawhole:

    strangeid:{A:Set}{B:ASet}(a:A)(b:Ba)Bastrangeid{A}{B}abawithBa...|r={!checkme!}

    inthehole,boththetypeof ba andthegoalstypeare r .

  • Fromtheseobservationsweconcludethat withexpr createsanewvariable,say w ,andbackwardssubstitutes expr to w inacontext,changingalltheoccurrencesof expr thetypesofthecontextto w .Whichmeansthatinaresultingcontexteverytypethathad expr asasubtermstartsdependendingonw .

    Thispropertyallowsusing with forrewriting:

    lemma+zero:aa+zeroalemma+zerozero=refllemma+zero(succa)witha+zero|lemma+zeroalemma+zero(succa)|._|refl=refl

    sameexpressionwithexpandedunderscore:lemma+zero:aa+zeroalemma+zerozero=refllemma+zero(succa)witha+zero|lemma+zeroalemma+zero(succa)|.a|refl=refl

    Intheseterms a+zero isreplacedbyanewvariable,say w ,whichgives lemma+zeroa:aw .Patternmatching on refl gives [ w = a ] and so the dotted pattern appears. After that the goal typebecomes aa .

    Thispattern

    fpswitha|eqn...|._|refl=rhs

    issocommonthatithasitsownshorthand(https://lists.chalmers.se/pipermail/agda/2009/001513.html):

    fpsrewriteeqn=rhs

    Exercise.Prove (onpaper) that rewritingagoal typewith with andpropositional equality isa syntaxsugarforexpressionsbuiltfrom refl , sym , trans and cong .

    UniversesandpostulatesWhenmoving fromHaskell toAgdaexpression every type isofkind * , i.e. forany type X , X:* transformsintoeverygroundtypeisoftype Set ,i.e.foranygroundtype X , X:Set .Ifwearewillingtobeconsistent,wecantafford Set:Set becauseit leadstoanumberofparadoxes(moreonthembelow).Still,wemightwanttoconstructthingslikealistoftypesandourcurrentimplementationof Listcannotexpressthis.

    TosolvethisproblemAgdaintroducesaninfinitetowerof Set s,i.e. Set0:Set1 , Set1:Set2 ,andsoon with Set being an alias for Set0 . Agda is also a predicative system which means thatSet0Set0:Set1 , Set0Set1:Set2 ,andsoon,butnot Set0Set1:Set1 .Note,however,thatthistowerisnotcumulative,e.g. Set0:Set2 and Set0Set1:Set3 arefalsetypingjudgments.

    [AsfarasIknow,intheorynothingpreventsusfrommakingthetowercumulative,itsjustsohappenedthatAgdaselected this routeandnotanother.Predicativity isamuchmoresubtlematter (moreon thatbelow).]

  • Alistoftypesnowbecomes:

    dataList1(A:Set1):Set1where[]:List1A__:AList1AList1A

    whichlooksverymuchliketheusual List definition.

    TopreventacodeduplicationlikethatAgdaallowsuniversepolymorphicdefinitions.TodefinethetypeLevel ofuniverselevelsweneedabitofpostulatemagic:

    postulateLevel:Setpostulatelzero:Levelpostulatelsucc:LevelLevelpostulate__:LevelLevelLevel

    Postulatesessentiallydefinepropositionswithoutproofs,i.e.theysaytrustme,Iknowthistobetrue.Obviously,thiscanbeexploitedtoinfercontradictions:

    postulateundefined:{A:Set}A

    butforeverypostulateAgdaexpectstobesafethereisa BUILTIN pragmathatchecksthepostulateddefinitionpromotingitfromasimplepostulatetoanaxiom.For Level therearethefollowing BUILTIN s:

    {#BUILTINLEVELLevel#}{#BUILTINLEVELZEROlzero#}{#BUILTINLEVELSUClsucc#}{#BUILTINLEVELMAX__#}

    The Level typeworksverymuchlike .Ithastwoconstructors lzero and lsucc thatsignifyzeroand successor, there is also an operator __ which returns a maximum from its arguments. Thedifferencebetween and Level isthatwearenotallowedtopatternmatchonelementsofthelatter.

    Giventhedefinitionabove,expression Set for :Level meansthe Set oflevel .

    Wearenowabletodefineuniversepolymorphiclistinthefollowingway:

    dataPList{:Level}(A:Set):Setwhere[]:PListA__:APListAPListAorabitnicer:dataPList{}(A:Set):Setwhere[]:PListA__:APListAPListA

    ItisinterestingtonotethatAgdacouldhavegoneanotherroute,sayGHCroute,bydefiningallthebuiltinthingsinsidewithfixednames.Instead, BUILTIN pragmaallowsustoredefinethenamesofthebuiltins,which isveryhelpfulwhenwewant towriteourownstandard library.This isexactlywhatwearenowgoingtodo.

  • LibraryModulesandtheendofthrowawaycodeNotethatwehavebeenwritingeverythingaboveinsideamodulecalled ThrowAwayIntroduction .Fromhereonwearegoingto(mostly)forgetaboutitandwriteasmallstandardlibraryforAgdafromscratch.TheideaistoremoveanymodulewithanameprefixedbyThrowAwayfromthisfiletoproducethelibrarycode.Tomaketheimplementationofthisideaassimpleaspossibleweplacemarkerslike:

    {endofThrowAwayIntroduction}

    attheendsofthrowawaycode.Itallowstogeneratethelibrarybyasimpleshellcommand:

    catBrutalDepTypes.lagda|sed'/^\\begin{code}/,/^\\end{code}/!d;/^\\begin{code}/d;/^\\end{code}/c\'|sed'/^*moduleThrowAway/,/^*.endofThrowAway/d;'

    Wearenowgoingtoredefineeverythingusefulfromaboveinauniversepolymorphicway(whenapplicable),startingwith Level s:

    moduleLevelwhereUniverselevelspostulateLevel:Setpostulatelzero:Levelpostulatelsucc:LevelLevelinputforis\sqcuppostulate__:LevelLevelLevel

    infixl5__

    Makethemwork{#BUILTINLEVELLevel#}{#BUILTINLEVELZEROlzero#}{#BUILTINLEVELSUClsucc#}{#BUILTINLEVELMAX__#}

    EachmoduleinAgdahasanexportlist.Everythingdefinedinamodulegetsappendedtoit.Toplacethingsdefinedforexportinanothermoduleintoacurrentcontextthereisan open construct:

    openModuleName

    Thisdoesntappend ModuleName sexportlisttocurrentmodulesexportlist.Todothatweneedtoaddpublic keywordattheend:

    openLevelpublic

    Commonfunctionswithtypesnotforthefaintofheart

  • Exercise.Understandwhatisgoingonintypesofthefollowingfunctions:

    moduleFunctionwhereDependentapplicationinfixl0_$__$_:{}{A:Set}{B:ASet}(f:(x:A)Bx)((x:A)Bx)f$x=fx

    Simpleapplicationinfixl0_$__$_:{}{A:Set}{B:Set}(AB)(AB)f$x=f$x

    inputforis\oDependentcomposition__:{}{A:Set}{B:ASet}{C:{x:A}BxSet}(f:{x:A}(y:Bx)Cy)(g:(x:A)Bx)((x:A)C(gx))fg=xf(gx)

    Simplecomposition__:{}{A:Set}{B:Set}{C:Set}(BC)(AB)(AC)fg=fg

    Flipflip:{}{A:Set}{B:Set}{C:ABSet}((x:A)(y:B)Cxy)((y:B)(x:A)Cxy)flipfxy=fyx

    Identityid:{}{A:Set}AAidx=x

    Constantfunctionconst:{}{A:Set}{B:Set}

  • (ABA)constxy=x

    openFunctionpublic

    Especiallynotethescopesofvariablebindingsintypes.

    LogicIntuitionistic Logic module:

    moduleLogicwhereinputforis\botFalsepropositiondata:Setwhere

    inputforis\topTruepropositionrecord:Setwhere

    impliesanythingatanyuniverselevelelim:{}{A:Set}Aelim()

    Propositionalnegationisdefinedasfollows:

    inputforis\lnot:{}SetSetP=P

    The technical part of the idea of this definition is that the principle of explosion (from a contradiction,anythingfollows)getsaprettystraightforwardproof.

    Exercise.Provethefollowingpropositions:

  • moduleThrowAwayExercisewherecontradiction:{}{A:Set}{B:Set}AABcontradiction={!!}

    contraposition:{}{A:Set}{B:Set}(AB)(BA)contraposition={!!}

    contraposition:{}{A:Set}{B:Set}(AB)(BA)contraposition={!!}

    :{}{A:Set}A(A)a={!!}

    :{}{A:Set}((A))A={!!}

    Hint.Use CcC, heretoseethegoaltypeinitsnormalform.

    Fromamore logical standpoint the idea of is that false proposition P should be isomorphic to (i.e.theyshouldimplyeachother: PP ).Since P istrueforall P thereisonly Pleftforustoprove.

    Fromacomputationalpointofviewhavingavariableoftype inacontextmeansthatthereisnowayexecutionofaprogramcouldreachthispoint.Whichmeanswecanmatchonthevariableanduseabsurdpattern, elim doesexactlythat.

    Notethat,beinganintuitionisticsystem,Agdahasnomeanstoprovedoublenegationrule.Seeforyourself:

    :{}{A:Set}(A)Aa={!checkme!}{endofThrowAwayExercise}

    By the way, proofs in the exercise above amounted to a serious scientific paper at the start of 20thcentury.

    Solutionfortheexercise:

  • privatemoduleDummyAB{}{A:Set}{B:Set}wherecontradiction:AABcontradictionaa=elim(aa)

    contraposition:(AB)(BA)contraposition=flip__

    contraposition:(AB)(BA)contraposition=flip

    openDummyABpublic

    privatemoduleDummyA{}{A:Set}where:A(A)=contradiction

    :((A))Aa=a

    openDummyApublic

    Exercise.Understandthissolution.

    Noteclevermoduleusage.Openingamodulewithparametersprefixestypesofallthethingsdefinedtherewiththeseparameters.Wewillusethistrickalot.

    Letusdefineconjunction,disjunction,andlogicalequivalence:

    inputforis\andrecord__{}(A:Set)(B:Set):Set()whereconstructor_,_fieldfst:Asnd:B

    open__public

    inputforis\ordata__{}(A:Set)(B:Set):Set()whereinl:AABinr:BAB

    inputforis\__:{}(A:Set)(B:Set)Set()AB=(AB)(BA)

  • Makeallthisgoodnessavailable:

    openLogicpublic

    MLTT:typesandpropertiesSomedefinitionsfromPerMartinLfstypetheory[12]:

    moduleMLTTwhereinputforis\==Propositionalequalityinfix4__data__{}{A:Set}(x:A):ASetwhererefl:xx

    inputforis\SigmaDependentpairrecord{}(A:Set)(B:ASet):Set()whereconstructor_,_fieldprojl:Aprojr:Bprojl

    openpublic

    Makerewritesyntaxwork{#BUILTINEQUALITY__#}{#BUILTINREFLrefl#}

    The typeisadependentversionof __ (thesecondfielddependsonthefirst),i.e. __ isaspecificcaseof :

    inputforis\x__:{}(A:Set)(B:Set)Set()AB=A(_B)

    :{}{A:Set}{B:Set}(AB)(AB)=(zprojlz,projrz),(zfstz,sndz)

    Personally,Iuseboth __ and __ occasionallysince __ looksuglyinthenormalformandmakesgoaltypeshardtoread.

    Someproperties:

  • modulePropwhereprivatemoduleDummyA{}{A:Set}where__issymmetricsym:{xy:A}xyyxsymrefl=refl

    __istransitivetrans:{xyz:A}xyyzxztransreflrefl=refl

    __issubstitutivesubst:{}{P:ASet}{xy}xyPxPysubstreflp=p

    privatemoduleDummyAB{}{A:Set}{B:Set}where__iscongruentcong:(f:AB){xy}xyfxfycongfrefl=refl

    subst:{}{P:ABSet}{xyuv}xyuvPxuPyvsubstreflreflp=p

    privatemoduleDummyABC{}{A:Set}{B:Set}{C:Set}wherecong:(f:ABC){xyuv}xyuvfxufyvcongfreflrefl=refl

    openDummyApublicopenDummyABpublicopenDummyABCpublic

    Makeallthisgoodnessavailable:

    openMLTTpublic

    DecidablepropositionsmoduleDecidablewhere

    Decidablepropositionitisapropositionthathasanexplicitproofordisproval:

    dataDec{}(A:Set):Setwhereyes:(a:A)DecAno:(a:A)DecA

  • Thisdatatypeisverymuchlike Bool ,exceptitalsoexplainswhythepropositionholdsorwhyitmustnot.

    Decidablepropositionsarethegluethatmakeyourprogramworkwiththerealworld.

    Supposewewanttowriteaprogramthatreadsanaturalnumber,say n ,from stdin anddividesitbytwowith div2E .Todothatweneedaproofthat n is Even .Theeasiestwaytodoitistodefineafunctionthatdecidesifagivennaturalis Even :

    moduleThrowAwayExamplewhereopenThrowAwayIntroduction

    Even+2:{n}(Evenn)(Even(succ(succn)))Even+2en(e2succen)=contradictionenen

    Even?:nDec(Evenn)Even?zero=yesezeroEven?(succzero)=no(())noteanabsurdpatterninananonymouslambdaexpressionEven?(succ(succn))withEven?n...|yesa=yes(e2succa)...|noa=no(Even+2a){endofThrowAwayExample}

    thenread n from stdin ,feeditto Even? ,matchontheresultandcall div2E if n is Even .

    Sameideaappliestoalmosteverything:

    Wanttowriteaparser?Parserisaprocedurethatdecidesifastringconformstoasyntax.Wanttotypecheckaprogram?Typecheckerisaprocedurethatdecidesiftheprogramconformstoagivensetoftypingrules.Wantanoptimizingcompiler?Parse,matchon yes ,typecheck,matchon yes ,optimizetypedrepresentation,generateoutput.Andsoon.

    Usingsameideawecandefinedecidabledichotomousandtrichotomouspropositions:

    dataDi{}(A:Set)(B:Set):Set()wherediyes:(a:A)(b:B)DiABdino:(a:A)(b:B)DiAB

    dataTri{}(A:Set)(B:Set)(C:Set):Set(())wheretri:(a:A)(b:B)(c:C)TriABC

    Makeallthisgoodnessavailable:

    openDecidablepublic

    Naturalnumbers:operations,propertiesandrelations

  • Considerthistobetheanswer(encryptedwith rewrite s)fortheexercisewayabove:

    moduleDatawhereNaturalnumbers(positiveintegers)data:Setwherezero:succ:

    moduleRelwhereinfix4____

    data__:Setwherezn:{n}zeronss:{nm}nmsuccnsuccm

    _m=m

  • >m(n
  • *isassociative*assoc:abc(a*b)*ca*(b*c)*assoczerobc=refl*assoc(succa)bcrewrite*+distb(a*b)c|*assocabc=refl

    privatemoduleDummywherelemma*zero:aa*zerozerolemma*zerozero=refllemma*zero(succa)=lemma*zeroa

    lemma+swap:abca+(b+c)b+(a+c)lemma+swapabcrewritesym(+assocabc)|+commab|+assocbac=refl

    lemma*succ:aba+a*ba*succblemma*succzerob=refllemma*succ(succa)brewritelemma+swapab(a*b)|lemma*succab=refl

    openDummy

    *iscommutative*comm:aba*bb*a*commzerob=sym$lemma*zerob*comm(succa)brewrite*commab|lemma*succba=refl

    moduleRelOpwhereopenRelopenOpopenProp

    infix4_?__?__

  • _
  • openDummyApublic

    moduleDataVecwhereVectorinfixr5__dataVec{}(A:Set):Setwhere[]:VecAzero__:{n}AVecAnVecA(succn)

    moduleVecOpwhereopenOp

    privatemoduleDummyA{}{A:Set}whereSingleton`Vec`[_]:AVecA(succzero)[a]=a[]

    Concatenationfor`Vec`sinfixr5_++__++_:{nm}VecAnVecAmVecA(n+m)[]++bs=bs(aas)++bs=a(as++bs)

    head:{n}VecA(succn)Ahead(aas)=a

    tail:{n}VecA(succn)Atail(aas)=a

    openDummyApublic

    {Workinprogress.TODO.

    Ifindthefollowingdefinitionquiteamusing:

    moduleVecListswhereopenDataVec

    privatemoduleDummyA{}{A:Set}whereVecList=(VecA)}

    Beingina List

  • Indexingallowstodefineprettyfunthings:

    moduleThrowAwayMorewhereopenDataListopenListOp

    inputforis\in`a`isin`List`data__{}{A:Set}(a:A):ListASetwherehere:{as}a(aas)there:{bas}aasa(bas)

    inputforis\sub=`xs`isasublistof`ys`__:{}{A:Set}ListAListASetasbs={x}xasxbs

    The __ relationsaysthatbeingina List foranelement a:A meansthat a intheheadofa Listor inthetailofa List .Forsome a and as avalueoftype aas ,thatis a is ina list as isapositionofanelement a in as (theremightbeanynumberofelementsinthistype).Relation ,thatisbeingasublist,carriesafunctionthatforeach a in xs givesitspositionin as .

    Examples:

    listTest=zerozerosucczero[]listTest=zerosucczero[]

    Test:zerolistTestTest=here

    Test:zerolistTestTest=therehere

    Test:listTestlistTestTesthere=hereTest(therehere)=there(therehere)Test(there(there()))

    Letusprovesomepropertiesfor relation:

  • ++left:{A:Set}(asbs:ListA)as(bs++as)++leftas[]n=n++leftas(bbs)n=there(++leftasbsn)

    ++right:{A:Set}(asbs:ListA)as(as++bs)++right[]bs()++right(aas)bshere=here++right(aas)bs(theren)=there(++rightasbsn){endofThrowAwayMore}

    Notehowtheseproofsrenumberelementsofagivenlist.

    Beingina List generalized:AnyBygeneralizing __ relationfrompropositionalequality(in x(xxs) both x sarepropositionallyequal)toarbitrarypredicateswearriveat:

    moduleDataAnywhereopenDataListopenListOp

    Someelementofa`List`satisfies`P`dataAny{}{A:Set}(P:ASet):ListASet()wherehere:{aas}(pa:Pa)AnyP(aas)there:{aas}(pas:AnyPas)AnyP(aas)

    moduleMembership{}{A:Set}{B:Set}(P:BASet)whereinputforis\in`Pba`holdsforsomeelement`a`fromthe`List`whenPis`__`thisbecomestheusual"isin"relation__:BListASet()bas=Any(Pb)as

    inputforis\notin__:BListASet()bas=(bas)

    inputforis\sub=__:ListAListASet()asbs={x}xasxbs

    inputforis\sub=n__:ListAListASet()asbs=(asbs)

    inputforis\sup=__:ListAListASet()

  • asbs=(asbs)(bsas)

    refl:{as}asasrefl=id

    trans:{asbscs}asbsbscsascstransfg=gf

    refl:{as}asasrefl=id,id

    sym:{asbs}asbsbsassym(f,g)=g,f

    trans:{asbscs}asbsbscsascstransfg=(fstgfstf),(sndfsndg)

    []:{b}b[][]()

    WhenPis`__`thisbecomes`b[a]ba`singletonP:{ab}b[a]PbasingletonP(herepba)=pbasingletonP(there())

    Psingleton:{ab}Pbab[a]Psingletonpba=herepba

    ++left:(asbs:ListA)as(bs++as)++leftas[]n=n++leftas(bbs)n=there(++leftasbsn)

    ++right:(as:ListA)(bs:ListA)as(as++bs)++right[]bs()++right(xas)bs(herepa)=herepa++right(xas)bs(theren)=there(++rightasbsn)

    filter:{}{Q:ASet}(q:xDec(Qx))(as:ListA)filterqasasfilterq[]()filterq(aas)nwithqafilterq(aas)(herepa)|yesqa=herepafilterq(aas)(theren)|yesqa=there(filterqasn)filterq(aas)n|noqa=there(filterqasn)

    Exercise.Notehowgeneralthiscodeis. filter coversabroadsetofpropositions,withfilteredlistisasublist(intheusualsense)oftheoriginallistbeingaspecialcase.Do CcC. inthefollowinggoaland

  • explainthetype:

    moduleThrowAwayMorewheregoal={!DataAny.Membership.filter!}{endofThrowAwayMore}

    Explainthetypesofallthetermsin Membership module.

    Dualpredicate:All{Workinprogress.TODO.

    Ididn'thaveachancetouse`All`yet(andI'mtoolazytoimplementthismodulerightnow),buthereisthedefinition:

    moduleDataAllwhereopenDataListAllelementsofa`List`satisfy`P`dataAll{}{A:Set}(P:ASet):ListASet()where[]:AllP[]__:{aas}PaAllPasAllP(aas)}

    BooleansArenotthatneededwith Dec ,actually.

  • moduleDataBoolwhereBooleansdataBool:Setwheretruefalse:Bool

    moduleBoolOpwhereif_then_else_:{}{A:Set}BoolAAAiftruethenaelse_=aiffalsethen_elseb=b

    not:BoolBoolnottrue=falsenotfalse=true

    and:BoolBoolBoolandtruex=xandfalse_=false

    or:BoolBoolBoolorfalsex=xortruex=true

    openDataBoolpublic

    OtherstuffWorkinprogress.TODO.WeneedtoprovesomethingfromAtoZ.Quicksortmaybe.

    PretheoreticalcornerThissectiondiscussesinterestingthingsaboutAgdawhicharesomewhereinbetweenpracticeandpuretheory.

    moduleThrowAwayPreTheorywhereopenPropopenOp

    EqualityandunificationRewritingwithequalityhidesacoupleofcatches.

    Rememberthetermof lemma+zero fromabove:

  • lemma+zero:aa+zeroalemma+zerozero=refllemma+zero(succa)witha+zero|lemma+zeroalemma+zero(succa)|._|refl=refl

    ittypechecks,butthefollowingproofdoesnt:

    lemma+zero:aa+zeroalemma+zerozero=refllemma+zero(succa)witha|lemma+zeroalemma+zero(succa)|._|refl=refl

    Theproblemhereisthatforarbitraryterms A and B topatternmatchon refl:AB these A and Bmustunify.In lemma+zero casewehave a+zero backwardsubstitutedintoanewvariable w ,thenwematchon refl weget wa .Ontheotherhand,in lemma+zero casewehave a changedintow ,an refl gets w+zerow typewhichisamalformed(recursive)unificationconstraint.

    Thereisanothercatch.Ourcurrentdefinitionof __ allowstoexpressequalityontypes,e.g. Bool .

    Thisenablesustowritethefollowingterm:

    lemmaunsafeeq:(P:Bool)BoollemmaunsafeeqPbwithBool|PlemmaunsafeeqPb|.|refl=b+succzero

    whichtypecheckswithouterrors.

    Note,however,that lemmaunsafeeq cannotbeprovenbysimplypatternmatchingon P :

    lemmaunsafeeq:(P:Bool)Boollemmaunsafeeqreflb=b

    {endofThrowAwayPreTheory}

    Exercise. lemmaunsafeeq isafoodforthoughtaboutcomputationsafetyunderfalseassumptions.

    TheoreticalcornerInthissectionweshalltalkaboutsometheoreticalstufflikedatatypeencodingsandparadoxes.Youmightwanttoreadsomeofthetheoreticalreferenceslike[10],[12]first.

    moduleThrowAwayTheorywhere

    InliteratureAgdasarrow (x:X)Y (where Y mighthave x free)iscalleddependentproducttype,ortype(Pitype)forshort.Dependentpair iscalleddependentsumtype,ortype(Sigmatype)forshort.

    Finitetypes

  • Given , and Bool itispossibletodefineanyfinitetype,thatisatypewithfinitenumberofelements.

    moduleFiniteTypeswhereopenBoolOp

    __:(AB:Set)SetAB=Bool(xifxthenAelseB)

    zero=one=two=Boolthree=onetwofour=twotwoandsoon

    TODO.Saysomethingaboutextensionalsettingand = .

    SimpledatatypesmoduleDatatypeswhere

    Given finite types,types,andtypes it ispossible todefinenoninductivedatatypesusing thesameschemethedefinitionof __ uses.

    Noninductivedatatypewithoutindexeshasthefollowingscheme:

    dataDataTypeName(Param1:Param1Type)(Param2:Param2Type)...:SetwhateverCons1:(Cons1Arg1:Cons1Arg1Type)(Cons1Arg2:Cons1Arg2Type)...DataTypeNameParam1Param2...Cons2:(Cons2Arg1:Cons2Arg1Type)...DataTypeNameParam1Param2......ConsN:(ConsNArg1:ConsNArg1Type)...DataTypeNameParam1Param2...

    Reencodedintotypes,types,andfinitetypesitbecomes:

    DataTypeName:(Param1:Param1Type)(Param2:Param2Type)...SetwhateverDataTypeNameParam1Param2...=FiniteTypeWithNElementschoicewherechoice:FiniteTypeWithNElementsSetwhateverchoiceelement1=Cons1Arg1Type(Cons1Arg1Cons1Arg2Type(Cons1Arg2...))choiceelement2=Cons2Arg1Type(Cons2Arg1...)...choiceelementN=ConsNArg1Type(ConsNArg1...)

    Forinstance, Di typefromabovetranslatesinto:

  • Di:{}(A:Set)(B:Set)Set()Di{}{}AB=Boolchoicewherechoice:BoolSet()choicetrue=ABchoicefalse=AB

    DatatypeswithindicesWorkinprogress.TODO.Thegeneralidea:addthemasparametersandplaceanequalityproofinside.

    RecursivedatatypesWorkinprogress.TODO.Generalideas:Wtypesand.

    CurrysparadoxNegativeoccurrencesmakethesysteminconsistent.

    Copythistoaseparatefileandtypecheck:

    {#OPTIONSnopositivitycheck#}moduleCurrysParadoxwheredataCS(C:Set):Setwherecs:(CSCC)CSC

    paradox:{C}CSCCparadox(csb)=b(csb)

    loop:{C}Cloop=paradox(csparadox)

    contr:contr=loop

    UniversesandimpredicativityWorkinprogress.TODO.*Russellsparadox*Hurkensparadox

    {endofThrowAwayTheory}

    References[1] Wiki, Agda Tutorials list. [Online]. Available: http://wiki.portal.chalmers.se/agda/pmwiki.php?n=Main.Othertutorials(http://wiki.portal.chalmers.se/agda/pmwiki.php?n=Main.Othertutorials)

    [2] Wiki, Agda: Documentation. [Online]. Available: http://wiki.portal.chalmers.se/agda/pmwiki.php?n=Main.Documentation(http://wiki.portal.chalmers.se/agda/pmwiki.php?n=Main.Documentation)

  • [3] A. Setzer, Interactive Theorem Proving for Agda Users. [Online]. Available:http://www.cs.swan.ac.uk/~csetzer/lectures/intertheo/07/interactiveTheoremProvingForAgdaUsers.html(http://www.cs.swan.ac.uk/~csetzer/lectures/intertheo/07/interactiveTheoremProvingForAgdaUsers.html)

    [4] A. Bove and P. Dybjer, Dependent Types at Work. [Online]. Available:http://www.cse.chalmers.se/~peterd/papers/DependentTypesAtWork.pdf(http://www.cse.chalmers.se/~peterd/papers/DependentTypesAtWork.pdf)

    [5] U. Norell, Dependently Typed Programming in Agda. [Online]. Available:http://www.cse.chalmers.se/~ulfn/papers/afp08/tutorial.pdf(http://www.cse.chalmers.se/~ulfn/papers/afp08/tutorial.pdf)

    [6] T. Altenkirch, Computer Aided Formal Reasoning. [Online]. Available:http://www.cs.nott.ac.uk/~txa/g53cfr/(http://www.cs.nott.ac.uk/~txa/g53cfr/)

    [7]Coq: Documentation. [Online]. Available: http://coq.inria.fr/documentation(http://coq.inria.fr/documentation)

    [8]Idris: Documentation. [Online]. Available: http://idrislang.org/documentation (http://idrislang.org/documentation)

    [9]Epigram.[Online].Available:http://www.epig.org/(http://www.epig.org/)

    [10] M.H.B. Srensen and P. Urzyczyn, Lectures on the CurryHoward Isomorphism. 1998 [Online].Available: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.17.7385(http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.17.7385)

    [11] S. Thompson, Type Theory and Functional Programming. [Online]. Available:https://www.cs.kent.ac.uk/people/staff/sjt/TTFP/(https://www.cs.kent.ac.uk/people/staff/sjt/TTFP/)

    [12] P. MartinLf, Intuitionistic type theory. Notes by Giovanni Sambin. [Online]. Available:http://www.csie.ntu.edu.tw/~b94087/ITT.pdf(http://www.csie.ntu.edu.tw/~b94087/ITT.pdf)

    [13] P. MartinLf, Intuitionistic type theory. [Online]. Available:http://intuitionistic.files.wordpress.com/2010/07/martinloftt.pdf(http://intuitionistic.files.wordpress.com/2010/07/martinloftt.pdf)

    [14] B. Nordstrm, K. Petersson, and J.M. Smith, Programming in MartinLfs Type Theory. AnIntroduction. [Online]. Available: http://www.cse.chalmers.se/research/group/logic/book/(http://www.cse.chalmers.se/research/group/logic/book/)

    [15]Simpler Easier. [Online]. Available: http://augustss.blogspot.ru/2007/10/simplereasierinrecentpapersimply.html(http://augustss.blogspot.ru/2007/10/simplereasierinrecentpapersimply.html)

    [16] A. Bauer, How to implement dependent type theory I. [Online]. Available:http://math.andrej.com/2012/11/08/howtoimplementdependenttypetheoryi/(http://math.andrej.com/2012/11/08/howtoimplementdependenttypetheoryi/)

    [17] A. Bauer, How to implement dependent type theory II. [Online]. Available:http://math.andrej.com/2012/11/11/howtoimplementdependenttypetheoryii/(http://math.andrej.com/2012/11/11/howtoimplementdependenttypetheoryii/)

    [18] A. Bauer, How to implement dependent type theory III. [Online]. Available:http://math.andrej.com/2012/11/29/howtoimplementdependenttypetheoryiii/(http://math.andrej.com/2012/11/29/howtoimplementdependenttypetheoryiii/)

  • [19] J. Malakhovski, Functional Programming and Proof Checking Course. [Online]. Available:http://oxij.org/activity/itmo/fp/(http://oxij.org/activity/itmo/fp/)

    [20] C. McBride and J. McKinna, The view from the left. [Online]. Available:http://strictlypositive.org/view.ps.gz(http://strictlypositive.org/view.ps.gz)

    RelatednotesReinventingFormalLogic(/note/ReinventingFormalLogic/)