This is a workshop I gave at Monadic Party in Poznan. See the source materials here: https://github.com/justinwoo/real-world-purescript-workshop-2019
RealWorldPureScript(Day1)JustinWooMonadicParty-2019Jun201/21
View Slide
PlanDay1:WhatisPureScript,andhowdothesetypeswork?IntroducethePureScriptlanguage,talkaboutsomedetailswithtypes,kinds,typeclasses+functionaldependencies,andthewhyandhowofrowtypesandrowtypeclasses.Day2:HowdowedoFFI,andhowcanweusetypestomakeitbetter?IntroduceFFIinPureScript,andvariousapproachestoFFIwithtypes,frombasicopaquedatatypestodatatypeswithrowtypeparameters.https://github.com/justinwoo/real-world-purescript-workshop-20192/21
PreviewofDay1contentsTypealiases,newtypes,datatypesFunctions,patternmatching,guardsAnonymousrecordsTypeclasseswithmultipleparametersandfunctionaldependenciesKinds,RowkindRecordsasatypewitharowtypeparameterRowtypeclasses3/21
SetupYouwillneed...PureScript0.13.0SpagoNode10.xorhigherInstallationmethods:ViaNix:https://github.com/justinwoo/easy-purescript-nixVianpm:npmi-gpurescriptspagoPlease,makesureyouhavesetnpmprefixtosomethinglike~/.npm:#~/.npmrcprefix=/home/your-user/.npmnpmsetprefix~/.npmrc4/21
WhatisPureScript?aHaskell-likelanguageforworkingwithJavaScriptalanguageforusingtypesforbothstaticguaranteesandautomaticallyderivedroutinesastateofmindasourceofmemesonTwitter"therowtypeslanguage"5/21
Helloworld(src/Main.purs)Helloworld:moduleMainwhere--moduleMain(main)whereimportPreludeimportEffect(Effect)importEffect.Console(log)main::EffectUnitmain=dolog"Hellosailor!">spagorun6/21
Types(src/Basics.purs)typeStringAlias=StringstringAliasValue::StringAliasstringAliasValue="Hello"newtypeURL=MkURLStringurlValue::URLurlValue=MkURL"https://google.com"dataURLorCode=IsURLString|IsCodeStringurlOrCodeValue::URLorCodeurlOrCodeValue=IsCode"banana"7/21
FunctionsunwrapURL::URL->StringunwrapURL(MkURLs)=sisCode::URLorCode->BooleanisCode(IsCode_)=trueisCode(IsURL_)=falseisCode'::URLorCode->BooleanisCode'x=casexofIsCode_->true_->falseisCode''::URLorCode->BooleanisCode''x|IsCode_<-x=true|otherwise=false8/21
AnonymousRecordsUnlikeHaskell:typeMyRecord={apple::String,banana::String,kiwi::String}Moreonthisaftertalkingabouttypes,Types,rowtypes,andkinds.9/21
TypeClasses(src/TypeClassesAndKinds.purs)Givensomeconcretetype,youshouldbeabletomatchsomeinstance,whichmayleadtoadditionaltypesbeingdeterminedadditionalfunctionsbeingdeterminedclassUnwrapta|t->awhereunwrap::t->ainstanceunwrapURLInstance::UnwrapURLStringwhereunwrap(MkURLs)=s10/21
classRodeoTypesinputoutput|input->outputinstancerodeoIntString::RodeoTypesIntStringinstancerodeoStringBoolean::RodeoTypesStringBooleandataProxys=ProxyrodeoTypes::forallinputoutput.RodeoTypesinputoutput=>Proxyinput->ProxyoutputrodeoTypes_=ProxyrodeoResult1::ProxyStringrodeoResult1=rodeoTypes(Proxy::ProxyInt)rodeoResult2::Proxy?hole--Hole'hole'hastheinferredtypeBooleanrodeoResult2=rodeoTypes(Proxy::ProxyString)11/21
KindsSofar,everythinghashadinferredkinds,typicallyofkindType.dataProxy(s::Type)=ProxyAllTypeshavevalues,buthowaboutsomethatdon't?e.g.Symbolkind:--fromData.SymboldataSProxy(sym::Symbol)=SProxy--Informationissimplyusedincompiletime:staticStringProxy::SProxy"helloworld"staticStringProxy=SProxy--fromData.SymbolclassIsSymbol(sym::Symbol)wherereflectSymbol::SProxysym->StringreflectedSymbolValue::StringreflectedSymbolValue=reflectSymbolstaticStringProxy12/21
Arrowkind->takestwoTypesandgivesyouaType.typeIntToInt1=Int->InttypeArrow=(->)::Type->Type->TypetypeFromInt=(->)Int::Type->TypetypeIntToInt2=FromIntInt::Type13/21
Rowkind(src/Rows.purs)Specialsymbol#,whichcancreatearowofatypeofakind."Row":unorderedcollectionoffieldsbySymbolandassociatedtypeofakind.typeEmptyRow=()::#TypetypeSingleRow=(a::String)::#TypetypeSymbolRow=(a::"apple")::#SymbolEnablesuser-createddatatypes,e.g.polymorphicvariantsasalibrary:purescript-variantforeignimportdataVariant::#Type->Type14/21
Records--fromPrim("builtins")dataRecord::#Type->TypetypeMyRecordA={apple::String,banana::String}typeMyRecordB=Record(apple::String,banana::String)id=identity::MyRecordA->MyRecordBfn1::MyRecordA->Stringfn1r=r.applefn1::MyRecordA->MyRecordAfn1r=r{apple="no"}15/21
RowtypeclassesWhatifwecouldusetherowtypeparameterofRecordandbeabletogetgenerictype-levelinformation?--Built-intypeclassesin`Prim.Row`classUnion(left::#Type)(right::#Type)(union::#Type)|leftright->union,rightunion->left,unionleft->rightclassNub(original::#Type)(nubbed::#Type)|original->nubbedclassLacks(label::Symbol)(row::#Type)classCons(label::Symbol)(a::Type)(tail::#Type)(row::#Type)|labelatail->row,labelrow->atail16/21
PureScript-Recordpurescript-recordisalibrarywhichusesexactlytheseconstraintstoextracttypeinformation.get::forallrr'la.IsSymboll=>Row.Conslar'r=>SProxyl->{|r}->aget=--...result::?hole--Hole'hole'hastheinferredtypeIntresult=get(SProxy::_"apple"){apple:123}insert::forallr1r2la.IsSymboll=>Lackslr1=>Conslar1r2=>SProxyl->a->{|r1}->{|r2}17/21
ReviewofDay1contentsTypealiases,newtypes,datatypesFunctions,patternmatching,guardsAnonymousrecordsTypeclasseswithmultipleparametersandfunctionaldependenciesKinds,RowkindRecordsasatypewitharowtypeparameterRowtypeclasses18/21
ExtrareadingGenerics-Rep(DatatypeGenerics)tutorialhttps://purescript-simple-json.readthedocs.io/en/latest/generics-rep.htmlAtutorialofhowtouseDatatypeGenericsinPureScript,whichallowyoutoworkwithagenericrepresentationoftypeswhicharederivedbythecompiler,sothatyoucanwriteaseriesoftypeclassesthatworkforalldatatypesderivingmethodsofgenericrepresentations."TypeclassesandInstancesarePatternMatchingforTypes"https://github.com/justinwoo/my-blog-posts/blob/master/posts/2018-04-27-type-classes-and-instances-are-pattern-matching-for-types.mdAgeneralpostabouthowworkinginthetypelevelhasmanyparallelstoworkinginthevaluelevel,withdiscussionofRowToList.19/21
Humor"FunTypeLevelliteralnumberarithmeticwithInstanceChains"https://github.com/justinwoo/my-blog-posts/blob/master/posts/2018-05-27-fun-type-level-literal-number-arithmetic-with-instance-chains.mdclassAdd(l::Symbol)(r::Symbol)(o::Symbol)|l->roinstancezeroAdd::Add"zero"rrelseinstancesuccAdd::(Succl'l,Succrr',Addl'r'o)=>Addlro"Wedon'tneedPeanoNumbersinPureScript"https://github.com/justinwoo/my-blog-posts/blob/master/posts/2018-09-11-we-dont-need-peano-numbers-in-purescript.mdresultSub2::SProxy"....................................."resultSub2=T.sub(SProxy::SProxy"...............................................")(SProxy::SProxyT.Ten)20/21
Somememeshttps://twitter.com/jusrin00/status/1012327213591605249https://twitter.com/jusrin00/status/933428832618545153https://twitter.com/jusrin00/status/963892030773579776https://twitter.com/jusrin00/status/1082058122393513984https://twitter.com/jusrin00/status/1053763021208723456https://twitter.com/jusrin00/status/985596999998328832https://twitter.com/jusrin00/status/968471589812670465https://twitter.com/jusrin00/status/1008330774884601856https://twitter.com/jusrin00/status/1132007452810063874https://twitter.com/jusrin00/status/1128059526404554752https://twitter.com/jusrin00/status/109419004417515929621/21