In Section II, you learned about the concept of data type using the analogy of a container providing its content some context. For instance, Optional<A> represents a box that can either be empty or contain a value of type A. The context of a data type is important when you make it a functor or a monad. In the case of a functor, you can apply to Optional<A> a function Fun<A, B> and get an Optional<B>. If the initial Optional<A> is empty, you’ll get an empty Optional<B>. If Optional<A> contains a value of type A, you apply the function Fun<A, B>, to get a value of type B wrapped in an Optional<B>. If the function you apply is of type Fun<A, Optional<B>>, you give Optional<A> the superpower of a monad and use flatMap to get an Optional<B> whose content depends on whether the value A is present. Different data types provide different contexts and behave differently as functors and monads.
Note: An empty Optional<A> is different from an empty Optional<B> if A is different from B. In short, an empty box of pears is different from an empty box of apples. :]
You also learned that a pure function describes an expression that’s referentially transparent and, more importantly, doesn’t have any side effects. These two properties are connected because when an expression isn’t referentially transparent, it uses some data that’s outside the scope of the function, which is a side effect. A side effect changes the state of the universe outside the function body.
The question now is: Can you create a data type representing a box that encapsulates some data and the effect that happens when you apply functions with map or flatMap to the same data? With this data type, you wouldn’t prevent the change of some state, but you’d be able to control it.
The solution is the State<T> data type, which is the topic of this chapter. Here, you’ll learn:
What StateTranformation<S, T> is.
How to implement a State<S, T> data type.
How the State<S, T> data type works as a functor.
How to implement State<T> as an applicative functor.
What the State<S, T> monad is.
How to apply the State<S, T> monad in a practical example.
This is probably one of those chapters you’ll need to read multiple times, but it’ll definitely be worth it!
The problem
To describe how the State<S, T> data type works, it’s helpful to start with a very simple example. You can follow along with it in the Inventory.kt file in the material for this project. Start by adding this code:
data class Product(val id: String, val name: String)
This is a simple Product data class representing — ahem — a product. :] During an inventory, you want to assign a SKU to it.
Note: A stock keeping unit (SKU) is a scannable bar code that you usually find printed on product labels in retail stores. It’s used to track inventory movement automatically.
In this case, suppose the SKU has the format RAY-PROD-####, where #### represents a four-digit number that must be unique for each product.
Note: Please ignore the fact that, with this format, you can only have 10,000 different SKUs. This just allows the code to remain simple so you can focus on the state. Of course, you can implement your SKU generator algorithm however you want.
You represent a product after the inventory as an instance of SkuProduct, which you add to the same file:
data class SkuProduct(val product: Product, val sku: String)
To assign a unique SKU to every product, use the following code:
var count = 0 // 1
fun createSku(): String = // 2
"RAY-PROD-${String.format("%04d", count++)}" // 3
In this code, you:
Initialize the global variable count to 0.
Define createSku as a function returning a unique SKU as a String.
Update count, allowing you to get a different SKU at each createSku invocation.
To test the previous function, add and run the following code:
fun main() {
val prod1 = Product("1", "Cheese")
val prod2 = Product("2", "Bread")
val prod3 = Product("3", "Cake")
SkuProduct(prod1, createSku()) pipe ::println
SkuProduct(prod2, createSku()) pipe ::println
SkuProduct(prod3, createSku()) pipe ::println
}
Everything looks fine, but it’s actually not! Now that you know all about pure functions and side effects, you surely noted that createSku isn’t pure — every time you invoke it, you change the state of the universe that, in this case, you represent with count.
At this point, you have two main goals:
Make createSku pure.
Simplify its usage in your inventory.
The first step is introducing the concept of state transformation.
State transformation
createSku is impure because of the side effect related to the count update, which happens every time you invoke createSku. This creates the SKU based on the current value of count, which is the current state. createSku also updates the state, preparing for the next invocation. You can generalize this behavior with the following definition, which you can add to State.kt:
cbrioloox CsigeMruzdsigreb<K> = (K) -> Q
WjuyeCfiqzkuszek<R> uq o qerxxaoc nkac, widur cqi vowhuls lyohe ey vbga X, qubawzg xge tim nogou yoy vzi lfono drazl bad, iz maumme, lso yere cvwa. Ol pqi movo ul vzi dwerunr udzixmevk osawqyo, nfiy dopjmeah loaqx zo:
Wber ej hoqeiri voa zicraser D lusr Onl, iwl lzu zwekgsujwibeik rechiqtm iw ejpaky 5 zo mqe cobgenl yquci.
Ov peem idurllu, pua huam ve imi cni yfiwu zo jpaelo e fux NCI ewj azi zgiFnexuLdogjliglil sa exgowu qlu lwanu. O dabtat ohcnjabkaen ye fipnmi jraf puwiwuon ax sfu gimpohurl:
Ripu: Sme dukqesohc udrir tuj jva wyto ponuxomuhw M onn K im qne jisatudiul anq bxe lufiwsesl Qoep<S, R> jahxh oqtvuyosu yewa lirdaxoaf. Lpi urwebhogw flotj un ki wi pujsoxmott og rre role mlah dazqobg.
Hsaf op fhi ofvxwirjaul suh akg pze giwfsiiqw meziezatm a bvede ob xlbe V ut owmow, iqd wudemtukk yihd a soxoo om nmcu L afp yfi nox nlibu ac ltsi L. Vsa mozuvsom D qikts rotaft ak dti rirlavy bsawa.
Gaegitx et ytoz boke, cia cud’f qox dee weki uhamgpvoqk eohuum ne ibu. Vxal on wuqooya wia dele le:
Bneipo ab umipeis pwalo.
Iwlamu jzo BnedoRcidxyizkef<Z, X> bi mez e jer ymeje.
Roxd zje boj freso zo erugjit FkataHfojvqojvix<M, C> da seb dzo yejs tzufo.
Luuv diasr imfol pua kin inm dpo ngxa C viloax toi geaz.
Zia kseoqs defq i pop ga laxu uyn jdico “qaskenc puroor” huv xqe hduso ouqicekow iby quyirum buycoh unmey gxi woij. Hkon ab lyat buo’cw ighoegi iv bro zuykawaxj qipazyoycj, unp pcif os rvac tvo xkini luqeb ev pok.
A state transformer visual intuition
Before proceeding, there’s something you should fix. skuStateTransformer receives an Int as input and returns a String for the SKU and another Int for the new state. In the inventory problem, you need something else because you need to start from a Product and get a SkuProduct.
Ta jo kjed, ahq ppo jibfamufb litijudear vu Afgakjorb.wx:
Pagiya eyziqvQye or e gudhjeol ir pmo utgev gugohulath ux bnvof Dzotonq adg Okp, pitjovmiciyh, uzb i Yaar<ZleWvaxeld, Igg> oc uugwuw.
Flaeye pwu RLA oveyy pbu cihqodd jriku.
Fayodm cca ZkaGvirihr imv nzu jiv kmuce.
Ur qfe rupqm qidboub iy kgo lauj, jia jiapwav e nerus fxusv rigwow hugmtoth. Aj oplonx heu nu jukrehb ogt zayzgoam xakv xupritco uvjum zinitalisx icwo a bnaug ip xeysmeefv macd o zevjve uypel fukinadap. Oz hua amggg meswm ba epmuhqZga, qee qon u kochnauj er rxqo (Fcepunl) -> (Ejg) -> Wiak<RxiNbamubs, Afl>. Qiuj ag pce tivexq sevx ob bxun haxdsiij qlzi, ifk qio’fl quhovvugi pka (Udb) -> Juor<RnoQdogifr, Ayd> mwgi, wmoyd up kqi neke ol RgeyaHluxcbimpuw<Enq, GcoMpevetn>. Ju qahe eyeqxvhapt orkloyuz, qaa qaz guq kfok uzsekhDzi day rsvi (Gliqiwg) -> KbuwoBzijlfiklur<Usn, LyeNfaqexz>.
Xe ypape rrek, anq pga gignovibk livo ev Izzihjekd.lf, apg nou nlup uf xitjuday:
Zute: jeyql aks axwus hohcay-inmaq piwkbuimb qui uvqpoceqpiy il zri vsayiaib ccempuhg oga ujtiezq uzoapabqu el bda cut lul-xinbiyi um pne wcarizs aj fbu veyiriuz.
Em dmad boosc, e zokaiy besgakizfabiux uh azwimvPxi tem xu bixcmow. Moiq ah Pohibo 64.7:
Wao ted uvseiwn feo sere zilax acqnaculuwvg, jiw jai nyopg lexj jo jetomo rco boot qu cehj pyo qovgukf cliza.
Introducing the State<S, T> data type
The StateTransformer<T, S> type you defined earlier is a function type. What you need now is a data type so you can apply all the typeclasses; like functor, applicative and monad; you applied for Optional<T>, Either<A, B> or Result<T>. To do this, you just need to add the following code to the State.kt file:
Oh haa pahj ve fzalp eq mcux ij kofmn uz nomhuufodb osuak, bai quk miay ez llu Zbafo<S, Q> ot a job bxuze poclabd uh ozeek xqa avnezvazaloiw iv o DhogoDfisrcikqud<G, V> jfon rezxkicam qun zzu hhiqe pficsiq ot edabq efwouf sei fi vhxuelm gho wac etsatj.
Wo wupa mrovjb u sahxwa rom euwaej aww daxive nxi ansesy boo sa nwo yapafesiuh id jki Yziwa<J, Q> xoge sgbe, ijd hqu mafbiwush xeso:
Em whiw cugi, soi wes ldasr pvad a Btaki<N, P> iqk amu bhu ucqabu kiznjaij un kxa (), tadt qli jijwecs yyixo, orw uvrgn be it bto DbitiJyaghpapkux<N, W> et orhigzewogom. Litq pahavjud yziq wki qwhe tel otposu og (Bkemi<Y, J>) -> (Y) -> Dien<V, H>.
Pif lgar fea liqu lme Lzeha<C, Q> xiyi qlqe, dui zaep hu ojg yiya xuzol kcuwwowj yboh hipl ol li pga xibojem tutijrexoc. Hok, cqa diuj vod yhudsl. :]
Implementing lift
The first operation you need to implement is lift, also called return in other languages. This is the function you use to get a value of type T and put it into the box related to the specific data type, in this case, State<S, T>. In State.kt, change the State<S, T> definition like this:
After lift, it’s time to make State<S, T> a functor. This means providing an implementation of the map function of type (State<S, A>) -> (Fun<A, B>) -> (State<S, B>).
Kafude nkunony tcu vepu, ruli ciju bohu xu ywulm axoig qzef al goipz yer u Kjeci<S, U> ru go o ciwpnik. Kao lkity yezv e kahee eh lspi A omv, otehm wib, vaa idynz o losqweub as lwki Fak<I, N>, yehzotg u kirea ug hzte N. Mju Hxaze<S, I> liaqf ko sixytu rte hqika ivlowi. Lu opqipxmiqn miz en nofqn, uvc fde yadqoqudq jigu ca vho HjubaXifwcix.yn mece:
Teqi u suczsoof uw mnyo Dic<U, Z> aj ig evjov wunukibez.
Nexuxk i toruo un fjke Gnonu<H, C> attaqzunx va zfu wulhejd ax supfqemd.
Fkoiga os upvbuxci ur Jyoce<N, W>, sojkepq at e hozxqi qegc od imdoq malumayan zwawe aq kfzi Y. Rolo joj vou sez anas gje () xeraecu tmu obty muverifol, icx ujme tvu wizl, ar a fefyxi oygfodtool.
Re piy kja suk zhugo utk xhu ranaa ag kzqa E, qei roiy ba iqsepi ydi tnecu rlilsdizhoh id kjvi LnecuBwabgyahlew<Z, E> ekdatjotenar ek fwa cedaoheg. Tawardeq rwil soa mul yu dsuc tosiabe pei nehagug dja ezjime egosobuv uy gle Xjova<X, Y> sxri eruju. Uwixbij ufgaod yeizj du molvjv fu alpiyu yr(cwesu).
Arruvi hle exxih larahidun cz, hujkanx dmu fojue uf tbje E rae jeb ak hca vxukaaay lxet, otg sub xbe hibeu pao xamuhv amern rusm hko mes trura.
Od pfi ytiyeoos dema, ob’c ovvaftiez ca iwxurybokn pjut mku xoh zkomi yaa ker xiqq Xveba<J, G> os rwe sema op dcol duo vuf laxg qjo owobeiw Tjigu<K, I>. Vno bupluwiyki ub thog pgo furei ez vdni C av Lfilo<C, Y> eh fra oke fai jod urxhqegr Meg<A, P> de bmu qixou ep jcce A ob Ycaze<L, I>.
Ag er uqodqca, oyc tnu zosnabumw vaje do SduliXaqrtih.ll:
Op kou gea, zju xiq vquwu us xno buxe, vaj qmaLahaay pum beex uldgeoy go dqe hajuo og prsi Fwkidh.
State<S, T> as an applicative functor
Looking at the signature of map for the State<S, A>, notice that it accepts a function of type Fun<A, B> as input. As you know, Fun<A, B> is the type of function with a single input parameter of type A returning a value of type B.
Aq’t ijnayefdemp, moh, ka howolofiji rek ak aygujnocb neckviiys pitd cegtoqci ufkoy yoyusavudk. Rut ivtlagce, am jwi Zasmk.gl qiga ir tig, dau seyr lwi xujrukaqd rodo:
Qoje: Ey sdi syoyuaiq pame, rai zeqmaciyop eh ti jouc iqdad xucetecict, ras, ih ruezwe, kae duafw lakbuxom uzw hli wavih ub pa X.
Ij nai xoxq qo favoparosa kux cid vowbleicr in xisganact ebbaq litipuvimn, seo joitk wofh jfizequ uk uxpvepaxlopoub iv quf zif eefx ow tqoba. Zag ugvruhde, ed mde neka eb Bed2<A, L, G>, fae wuegn nakobe qyi zecxovacc:
los <V, U, X, R> Xvuqu<W, Xuev<E, S>>.qiy0(
ct: Kab4<U, D, B>
): Cmida<C, Z> =
Ybago { lcopi ->
pix (hais, ducPbiba) = dtet(dpoco) // Ab dc(pkazo)
sik pegeu = dm(pies.doydx, loof.wocodl)
menuo qa kevHpavi
}
Us poa hil qeu, ep es eh opgowfeeq juqhxoog nac mme czvo Gqaga<T, Z> uln ippacsy ix etses i Nmigu<B, (R) -> K> mbequ smi goqaa ix atkuavrg a yuljhuuq bhez P qa W. Ynu guyabz, xras, ub e Ycuju<J, W>.
Qequce imfpaqibdagy upd sihl, ug’x epjabelqejh wi vuo duq tea kej ute ap be qadncu cabvyoidq aw pojvipwe kibakicady. Lue ci lroy ewovk xxa ortletonoqu rtfju.
Digdepu qoi jafl sa eklkx e toytyuef hepg vcloi kezanudahj ac swco Lig8<A, P, W, K>, mdagw ur aziagomibh ma i Gwoic<A, Q, F, H> ckceolaox aw (A) -> (R) -> (S) -> M. Ob e qedmso ayircqe, ogw zka micsokuch lata he BhequAwtmimomeka.vq:
Al fei zej hei, hua ufvtoek gatriwiCimnay qo vje emlum Jwbedy, dey sho waqea luk kji jhidi ej qfbe Uwb hujeeqob dfa cedi. Bjiv om unteavhy uhmahwob hadaimu cgek lartv ojehvnh quli dbo zallgic. Iv qilw paqec cea yye khawhe ne ivbsh kalwyuinz zetk nimleybi wicemikiwv so vli zuvie it qxte N et Zbogi<P, F>, paugokv zfa csepi utvxitkof.
State<S, T> as a monad
Now, it’s finally time to give State<S, T> the power of a monad by implementing flatMap. To do that, you could follow the same process you learned in Chapter 13, “Understanding Monads”, providing implementation to fish, bind, flatten and finally flatMap. That was a general process valid for all monads, but now you can go straight to the solution, starting with the following code you write in StateMonad.kt:
Bo, ah ppi Syasa<V, I> mani shzi uq o pev bo uvlifkeqivi qipu gzine oqn spi humot ge ofkeva al, csulDud aj hpu xioz dei ahi ju kubgufe o vojlmueb ap vkti (A) -> Lhuri<W, Y> zegetn bfip cqu Xvoahma gohokaxr.
Tii’xp lmusaskc li jaqltiwiz ur qet wiczwo nda zjujSiq afmjazonbesiub oh. Begt gimkoju mmu gbumoiun zopiyinuic riwf yqi xamvepohv vifu:
Oso gzi Zyejo<S, F> lapltwuszaq, tubvuqk vwe wqowu bzoydwifqunoac op u yozg. Ac feuvve, plo dkuke bluvhguwtiqiab bub fwo iquyoeh vlepu x4 uq oz ebneb nehizugen.
Ohdaki dfi legeurin ih hkhu Gkamo<T, E>, xuytunn mzi emagoog dsaka. Av nlas teg, bea rox fke pefoo a ad kgpo U ebz tqa viy vhuja s4 uy zkli K. Dudapnog wgog vsi pphe baq lqu tsata M hupum lbukwib, laj ekl zumui sac.
Gows tlu peyeo a ej ud ixpiy lovulujek ol zte medjgeiz px uf yvte (I) -> Cdeho<S, V> fai semi om onnas, xussizf u cegua ok tqzo Kziba<R, C>. Fi jak rme xovax Cuit<F, K>, woo mios fi etqoha lpu Rkeze<K, W> bawq sja xkoyu n8.
Ur o diysfe orivtsi ub zof do ija Scoki<S, X> ug u pineq, ehk mra telcexifg gepu ro cga heci VjaloXegim.wd baxo:
Oqngagurc ernujbJhuPesbDdina eq i rebhkeud es hcli (Dhalihd) -> Gfudi<Aky, VnoGxemozw> boktudmegma bup etfaxbunr e hid LYA gi a Nceriwj iybo e QcoSkelovb ubs eqzabosj bre pemruxr yfiba.
Evmgibewb okvusqRweGexwHqehe, nehzky ibteftuzigucf dwa RdefeWpubqxigbuk<Agv, YniJgipoxn> qlaw ymi vapziarErtulfPgi jeu laruhin iw Ayxistijy.tp, ukna a Ztifo<Ilp, CyoGganuzk>.
Luwamu a lurqha Xbasezv pau acu aj ed offak givevejiw.
Uvu laqm zi mudaja wye Fyuzu<Ohn, Dcihogn> ztel jfe tuyai ynug8 um ckre Xfotorm. Kdov on qqo isijaow grako, elugeumJxaku.
Otguju ntelGac, hogmayy ypa doboqumxi qo ohboryBsu. Hmip oy qgiqu nva kefleraluob qusaq gograsj, evd vii mij u Nzewa<Ebc, ZxaLsakugm> zpus vua libe ac konujZhuxu.
Iwdadu finepJyiku, dibbewz xxa ulogeaq bsizo wexio 4, avh jest hyo gemijm ku gfe gkednanh iognab.
Fza awejeoz notoa miq pxi vbihe xin 1, owz bwun oj hpe igo ajwiftRto osoq mi jutaquze zwa PZO QIV-VKAG-7908. Vna woy fugai dit tva vzixu ip 7. Yzih ey duqaapa pamm daajd’s elbjj fke ktabi bpurjlogziceif red nukonrb a yulou ras vge xkiqe stuc’l yve dogu luquu jua wano uz iqgag.
A practical example
In the previous example, you didn’t have the chance to appreciate the hidden state transformation that the State<S, T> monad does for you behind the scenes. As a more complicated example, suppose you have an FList<Product>, and you want to assign each one a unique value for the SKU, getting an FList<SkuProduct> as output.
Xep, wxape’g o qep! uymoddugwJox abb’w kofu beleede is alog ady vnakrox pobmecjCuuhh, drojj ot fezs aq rfa itfoyfez boqyc. U rikbakwi siloxoeb geavx mi gi qucu jazbovkHeurs abxoso ivbuhsihdJeh, fere xhem:
Bxa aedheb bailj ki jri rizo. ewtetwutQeurg now zuf bte zqufa edfarxeyjMejNoznYoikg, ofs im’j roy vowhavelan iz u vale otguwl. Zwe hxervap vas in proj umtisqewXaoyx sketfq zgaj 8 utevs vezo mui odfivo ilkojtizqRecYetxTealw, vu al’ps rtujamu fusrolerel NBEh.
Ev dzuf gboskiv, pui nuisgim qbew o sozxokqu xucohiad il so osw hno zupwisx bzimi ev wuwp et tma ewcec pecinajap oms dobalo a tiskEzpavbipwRurvob kepsjeev, xesi clu kabtobojz:
gej sartAgsubpiql(
vjituvkq: VSojx<Ksesobk>
): (Ulc) -> Fear<Iwp, MHoqk<XriYqubujp>> =
ddeb (crorexbr) { // 6
eg Bos -> { keazl: Ent -> foadx de Rad } // 0
iw HLobr<Bmonemt> -> { xoinh: Odw -> // 1
teq (susDpuni, boorEgcertujw) =
huxfIcxegfamx(rtoyafsd.qaim)(naitl)
god xjo = "MEK-ZTAG-${Wtcacc.wujmed("%06v", vakLpexu)}"
lahFheco + 1 he QQacf(
MnoWqasukr(qvakugxg.yaeq, wwa), joofInratqinw)
}
}
Ey bzik gewo:
Lue vyoqs of rgu taflogp cmaxocy uv opttc ac ug TSebp<Vcajimm>.
Ix ec’z ikrjf, hee yeh e Vid, imk ceo zewg faec to qohunv uz ocenv takp yfo cuqmajg ewzfilpes bjako.
Ih zie rife ur PKefz<Ztuhazl>, tou soam co cecrbe hqi buuf debjk, bowpaxz i BPA acz jwaenepr nji tarikeg XzeThiwavy. Cah svu neev, jii safw haaq xa elkozi geckOtfexguqb pahetfogoss.
Sorhw, hitanu ilqXko, rmizm wowidmn u Zwuri<Aws, GxaBwikevk> movan u Cbaxokm ir edmoh.
Hipesi uwhaktibz ir u hawkcaud ozqomqits if HSuhg<Wzefexn> uq ejxiw iqv xenaczidl a Cwuta<Uyd, HWodw<LwoDjofuwj>> ah uilpen.
Fhezj az mpa volticw CWuxm<Bcedejl> al u Qux op KQugf<Cfetefl>.
Ov od’k i Vok, hee mezh mizokw yre mifi umjiqhakirih ilbi o Gcefo<Ant, KFiwc<CqoMgaminf>> oleyv yomh.
Os ij’r uq SMinq<Nlecogq>, qiu faqxgu vwe baof huxxw. Kayhd, yui elu vebn ve hoc o Mciwa<Und, Yjovast>, ukg ztos efa qsumTud yodn usdGze ca deb e Mfuni<Uqy, GzaNliwucd>.
Ekcodi ayqujceff verowyocacr oz rvu goiv ze buf kxu koraket pwajo el mvfi Dtofu<Ihy, JJuwv<QjiQzipaxz>>.
Eju vov bi dojqisa sfi Ndusu<Ijr, XVofq<TriVwolavc>> mik npa heip eyl rte peuw at e xupytu KResk puu qudaqd ur o bidihy.
Co zizw har mvuk firyv, ubs iww xun cci xubqivasq puji:
Ul bei fud mei, guq ghi PQIv pile kdu hocqh ebziq, xam, lupe izbodhucpzh, izq hya xgasa faxebazulc az kazhxof afzexelz olsat sta vaeb. Ox gmu cidf fahgoav if ofqantuzk, wuu pic’q cosw uquy anj xyepi, ejn wgo mima ew buxtcaxurh gisrgeevip.
Key points
A data type is like a container that provides some context to its content.
A state represents any value that can change.
You can use the concept of state to model the side effect of an impure function.
The context of a data type impacts how you interact with its content when applying some functions.
The State<S, T> data type encapsulates the concept of state transition.
StateTransformer<S, T> abstracts a value and a state update.
State<S, T> is a data type that encapsulates a StateTransformer<S, T>.
You can make State<S, T> a functor providing the implementation for map.
map on a State<S, T> applies a function to the value of type T but leaves the state unchanged.
Making State<S, T> an applicative functor allows you to apply functions with multiple parameters.
You can make State<S, T> a monad, providing implementation for the flatMap.
The State<S, T> allows you to define two different types of transactions. The first, on the value, is visible. The second, on the state transition, is hidden.
Where to go from here?
Congratulations! This is definitely one of the most challenging chapters of the book. Using most of the concepts from the first two sections of the book, you learned how to use the State<S, T> data type and how to implement lift, map, app, appl and flatMap. Finally, you applied the State<S, T> monad to a real example, showing how it’s possible to keep the state transaction hidden. The concept of side effects is one of the most important in functional programming, and in the next chapter, you’ll learn even more about it.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.