From b547171a325262250d7fd74ec263ae1df9eb814a Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Mon, 17 Jun 2019 09:40:32 +0200 Subject: [PATCH 01/17] Create christiaanbaaij.json --- data/authors/christiaanbaaij.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 data/authors/christiaanbaaij.json diff --git a/data/authors/christiaanbaaij.json b/data/authors/christiaanbaaij.json new file mode 100644 index 0000000..688ad92 --- /dev/null +++ b/data/authors/christiaanbaaij.json @@ -0,0 +1,10 @@ +{ + "name": "Christiaan Baaij", + "bio": "Christiaan Baaij is one of the initial developers of the Clash compiler.", + "image": "/media/authors/christiaanbaaij.jpg", + "weight": 1, + "social": { + "twitter": "christiaanbaaij", + "github": "https://www.github.com/christiaanb" + } +} From 81d95acdec75d73097e928f1b84ba9deb5bd8b99 Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Mon, 17 Jun 2019 09:43:18 +0200 Subject: [PATCH 02/17] Add christiaanbaaij.jpg --- static/media/authors/christiaanbaaij.jpg | Bin 0 -> 16449 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 static/media/authors/christiaanbaaij.jpg diff --git a/static/media/authors/christiaanbaaij.jpg b/static/media/authors/christiaanbaaij.jpg new file mode 100644 index 0000000000000000000000000000000000000000..af78be1f4a04e8df6e3e985e24cd7c4988b243a9 GIT binary patch literal 16449 zcmbWe1ymeCw>3I2cyLK@cMA@KOYi`}o!~CPEjS@SaCdhNGB^ZxcMnc*4^IApeEQ$J z-g@uNTE+CxJzaI^BYW>U{F(o=1PBBmz`?=8!6LxJ!y_UhAR%L;AisKrjE9MZhE0S| zLQI5DNJvV_OhZb}NI^(Q%T33~!pgzHK|%u(;9=uuX6ImoLPSJFeua#Sf`ZFNMo7l? z|M~T&9e{xVRSZ=Ogdzt(V?Y5hp#F42nyGKCam!Pk~ zA)zs`aq$U>Ny#ZWxq0~og+;|B)it%?y84F3rp~VJp5DIxfx*eC>6zKN`Gv*xjm@p? zo!wu1`)B7Dmsh{9Z*K3P0KmWIKz{x;=s)bifY<{K0|SJCf3^n-+7&W@7%;G8tZG(=4su|2$>W-bfr@1Z|>U+kdtjtl<&`MYXr8P!8Q&1%u59x+(Q3enlt zrkm^VR9_a4A_S2ln<7Js9u1xn$V-AvUAUeMdmJlJ{5|0VK1k{#wImNEhF|SzbLU+r`-$~Rgw4Rd7HQn!Qwv=;D+X=A+1D)X) zYdA@;>oQ{Wh7fc)X;}ClszSPKZsR?eJz@jy)JM6r!bfu4f2%8rF)thIzkx5w=vyos z+a&TZXEtd3;Tm!1eZyOH0XNP%Rr%^*DquMQB&&GM)kLxfxD4E3qFusCz5*e7g)LA7pBzJvr02cUPtHo1&@hE zx#Q#?L1K^S*Nambz62n|#k+f`cw->(^Bf{C!IYN;#Eyf6DkS=$Nb~;@6n_IkX`Bpl z;EM!tT!?cPK!RAD6f+?d5@nRAg~V}S!sPy?dci_4z;NGV`gQ$*1?8C}1zDmy%ooKz z%1>x|4TP?HIvM$;qtyP#V~2N<(UheaRVMNEu>FkeK?Djg`dezI^&892OIrHTH3KTegu-*m5@5I(>7k;?txy-vOm&kT6Zv!)M6BYFugx z(l2&d)p-fpv!z!fj1F__Fdt&{@!xG`fOoZigbRVqGPJEMUN5AME__-rA0Vubf}8T| z2NI3Ck4j`6*;(<2z3apx=odVVmX~l`O7r%fiHPOk&3+w|nzRr=!O~?00z`_+qgDMb z@b4*?TWgKBb!8jcj*s#?uLBKGWcPsxT}v*?X2(ftC7-hE8tpbj-GrhKe$jVFiCcK| zkQlRdP97OtL&3yT%pX7LmWYc^>g)v~%K8?5okz)Rd;vzqp+%pWC6>_WotEZDWjv(84EA`h{eXfNo{Fr3R zm3aIlN_>wDOZ)_95@T8z8vE-^c1i2TAFq^29^*2_K63X^CLDK>_DVRO>}k1h*L1Nd z*lvJ~1o}z7@{?pgdMKGQdU@^`ZmawOV4L{TGzdLp%Cn2^R@LVgNs}k~a;h?5N;SCT* zd8rpMf0Ok~R3MuFs~#wglR`oSlFzkXiUj0a`p>t33{v#(iV37p)0r|GpVc>ACnsVC z&|dQpGmdzD_+5gkD2w@m1KIR@sN2NNXbn8n*MQHIyIHo6fh=mBxo98l*T zMhw5HU*H6-vZw@v5zqX>7y80X8AHbvx9E_!t|0ITf1@@&PTJXFXL0dmV7^=5%S+HV zqqi_^Mwv&#U-p|uf!X64b4Xf@E2_v<$CGn9qk;`TR)J{Nd2-_u$?4$kFRO{S9H#yQ z*h386o&sJm5Z`bjF;4^+ilBAmqyb8h{vKgC3JJ3bBv>}h# zj*}$Q?<)q{0}nFyR4S&%8d}~7zh;?~P#?!id%`P_6&GXAL+A2#0ysX%IEXy?M3qL5 z1j`;PMYPA;0^r*`(LY%+OQ4}s#GnEm{s4N*l5tdMTqtQS1p031PDn;V(O<1N*(;yys)LJQ_^EIi|>7o7MW`UN~`JqJwahTD{ zfWPGU+Mkfkr$4Sjmv<;WNS+<(1u?}-si>*|k0W5ssBLhJpqzGNpa8t9Csek&9%u(KQfS`2su^P#AInn>HGoI zBEk!u5~lo?J;Fe?{vu65B`-vFLpVoMJfA0Ij=o5}ca#j$6C?5ItY9ZsIdq5aA|s#} z)%fzUcu&hU2%*9zTG@#!I$2w&dt_7yQ~kUmg$RT3%SDoy)G3_YP$Xl9W191#yxjQVZVJ^1Q=^H>?1iu+IE$GoIyY z>Wb&luT%k&! zyuT#k87e`FLV~~OvwtVVB>crgv^hzz*tH*^AgttN=#X?DDIV1Zm*pDrZx}}fJWw1* z_WX!<^`6<#zZ{Tp2*Bq7Q^Gw^>8C|T8(d$>erCjd2Wa=So3p*MKF zdZAgrin5#SXgT(RWO%OB?fgOO7aY{}F(I>nAIu*B{rQbZX7QqliEgfF_ENJN=CAdzcPf@BFVYgLO0@YFiZ)*xSj8LU|BkZ7{V+^;fcz~vo z25g~Q507_U=H6!Qt3XpOJ`yt?R^-iVR1OO->L?=*$9}6UO=;>2$gKcjALVi+ckIb8 z^C=k-)nWwnC^z`>&`VOJG=V4t!9;^3El^{#QN$lNjyQVXmtIRB?CHF-y6?axI+*>e zXgN90jxGWpt*1lr5gf?WA>>0?`3IoYWWkpkQR{V(>LP==jr+CJFSvuDwUvE-qb=@K zuKSH1vA?#M{ni&GqlVrsgKJ-*@Xv#<#dshY0&xs}*~7Kc?Z&JkHJp01*NprF;X6Fx z)qp4mzKB2)MYT~E4*@D#T-+T0cQ35z86!gIy5R@Nb7kdIQV!>Okt85QJ|~%cLLA%o z1uWM7UjhnIQJ#RuBygmSbmg`wsSfSD!=}OSX$o3l3w~E;B)&nr2k%y8%bUZ^e{0n$ zC2oPSTE|Aola{A%Dm3$b*nm5Uyuu%VUVf^Gxra+aD&q&@2E2`mjqF<8x`RlW%vMrV zz)p(rbzzDTT_3bxHi{S-1(+cX^|s`MtdBaDnKnYLC_cigShJpGCrN`a?3{O+%QEWR z?QWV`bPL!cwbGPgLJPVZovURm3+!5 z-&?F`u8)oHJ@I(gzy0v;HG>%dI3}hiD^SdK>+5%M+2fJXw$^=CbKX^8<=^%d?F~J- zC{djQ&t_$#>*HCsq9WHvnzKtCNmnX80A`Oaj3|GYz)@M?Z zB0qm{Yy;5Ih~s>lZHDw`R`CSm;Sl1(Z#wtK0;SNw? zC*<*bx-tO4ACHy?pT+6Sf7g3#*M2W`xW8RW03P(%$t@6GIUBpG-P@E;?=sO6Uf=rk zwwkRo1yJ=CI}LpyAR}(P@Ajd;ke$e^4e zX(EoTiU&cqQvcFEpds83j_Ti77ZVb^1JAPPUo;D;_%EpT?>q95<@Mof6t0o^U+mL! zZ#K+d%X(T+3YU2sLT;aP=4VupXXzdz{G;61Ew8-17D+U*qt}PNW8flvdMzHe?HY7~ zvhY}`8m=26bxSesO!8E6nZ=Sz96#bFIxKEI2jj5QqmpZI2Cf#*k&b&~N1Ad~xP z_z*{1pGX?7Z(VCR4O6(URrpN80YPVzAMM;6W>oKKM?++RA+V!wpq^%qQ;W#ZJdQt> z{X5GIWF_C1GYCr=M%~V*i39?P}nuV;3y?R{T1_a`of+<%zN7QUbmg7{`~eZVrhQED%%032wya<1$T6Mzv&n> zu!&Aig5fQERo=uW^S;;}kWjpE-@IX&4nzV;LRM8m0372Mb2coaW*Nq7Tn`+hAawC* zoO@ZCZ}K%Ey?15o-xHIa$99P?arMz+%^j>f@wjkDWXAaj%W?*7xCU z4-94ormaUYOFA~?&s4mh`@;P>yP=1D=qIg&&?oz2c~Su2*G-T|OF2S8iV8CE|(Q~L39ngkj%CeyEo?2TAPxTi{% zW49L5hjl)?NlZda)H56Ut9XlJzX%P2p|k~3N)s=-!HWd(4-Mhv*mR%ko4X^xK0fS( z;#M7Jqh6kS zO&8ZDYv|Qp%0503p3?UR_z8x9yAQbl01I7Tq0ymb*y=XJtu0FPV-k=KSFI1Y+E98# zqlMKw=Mey|I~>?9UWTva{6!_A#Hwmb0V|qjB=84NP7Q8Uv@mz?3wL5b;g+pSLD7h0^wb_mP}2!!CK#6d4Rdifm+$7O zrE55MJ%MYRxD~^7Xf;ad|9gWfXcg!7le#{?w;*`QO%Ub1Eq;EIdfyNm3m$P8`#{-U zO2Z|T|qXJFhD_z_JFw&hEl$fH`+a`emRQP83ySVN0J!?#+^>rrlH z#qNCE)(MMhagfFe&z1(bZqzce6MiF){Xvp%I+0^$yoQ4k0gkK~G@4rZii=myC(SL) zO)^{kS?ZOA;~L>cZjnGFhegZ%vRU!vomvd6c4CbDHyYvxHMu166Bo8+KP^+$3tdlU z_iN4xtOV1OAjXm3+1UD@FQkIK&fP1s*TW4%6jkVb0njb#>(jI;M`5?H27Bg4&tCts(}Mr}$!O1l&LZYNUHsq2k{-elVm*^h;*HvNiao|R zO6YTNI%_t#AImM=+D~d!N!MgA&;=~tBIcCJM!1}|{4T@4j=1~-aB?;(=Ls8!I=b13 z+W>=tlQzL3>}yWN3t!aYYkGN#O?t4Ix%!dTzZfj<`I`+&96Cl=<+qyxL!$vGzI0kU zCGren88zb?gw?+AySgZ?--7}0&}H=3g+&J`78;|<4$D?sWWdn&87eB5fIfR&eb z%T4ERF%d>Y3Np#nze;Oj&)_L6PaQ|xe`f=O97Jp#;K8no8OEcVX=+3xNr|LbH!32j zBgCJtX-1Z|jzGU=DrRj{80$^lxhw4Psj(v~E9>YVe)Bj`hAXU(X!=uGxdsBkiB@lQ zLKip;DDMbc@auB(M+>G@po04is3BVC)j?tP+110uVVh`I_!Q}_S2Y8i53)>!i%wrX zA-pI8ahh6sTM}8-JqH~DpVzLp<7E%XAr^;k-$v3C=k~(LM1QxaG{IM5%@`x&s`n4T z)DoYgYVZ|@!rTKx+0?FdHnN++{45)HM4^GzQ?`byKuJYYb8Tb)))!9dbW-ymIqK>q zrzL;SZ1_FRE4mC_1LA`Pf`YLmw9iUu?A^W(W7NNeL@j&L$fz>(y@kKtsu*JZ?uR<4 z#YE_3vvN9gl-AAYIsGArDbAHoe)^+X!O)$$l~Fy)eD|Iiwxrz-u!!_0G%A;|3C)cfDZN=Bd~ z+i6{ki;Cqm+mA&;PfcT|!xB^`#$C3HK2X|;7Ikzuqi`TjSvm2Lx(WvcCEi(=>3yYZ zYwNc%2$%U;mnE#?E-=m|liY+zU>d*-Ugq{?v1!$`?K#5Hhys9lp{&t%Q(|l8fG?Yx z3zd$>QCd9D{0jipLOaxKSVOtLgoQM@w^P9C%dF|h1xlg09;zF4GhYFLG>zY$j@<1< zfk{6NbxrbwtQgX|n4M9kR@NG3861PCFgII9yr>c!4^P=d4QW#iW;U7oRappG0;1sF z14CW_Du~~#RZv#tlL%q#o|cYIpT<@&8-rKA~MMy|~o{f!0c_V|=U2_&mI`XCKWHk99(t?X-QTOYG^v8i+N{qxrif*wuf!eBt^|)KGprS-&H0lm|c4GVb6nizqfg!Oh z==eE|gb~xlLCVh;KZsjY=M2&PCFLzovIp0WO)c4i%NM>m?c#J(bqaLnCmF$9ooF>Z z)rHtmB018CgkJ2-wPsptV8ZGvNl{fMYk@ZyCE37POz=f7KuF6->c@5| zG4vF&7!PRkvY>~~AR?$xiGU{TazxgMzLpRZKr@>kE+vd`GHPka^QsR_DKcOkT`%(DfU$xs=>glI(*|orjV~jYdB1O8Ty^6Ik}! zk@QqTRGt}0@{`y_#c{EP8pd9V_3LQD;69q^E9!~}|E8?6NanKToh?Xq(TsYQSRjez zIfE!YcM(9i{NKHM+9-dd&Qt1ND6(rAWqcqXxDEKk-Z8>7{Dn~#IqfZwXrCHow-nIrHI8;sidEz$Z2bj> z*wR%ZWFh%`XI(-Fv9L>rtH3~!6bk5*tj&77dgc?D>T#odKxq)&ID+TF((CmO!IBuG zQkkE&)zLoMjY_Us#sVLSy&MK-po$rQ#hsBa_lA?#o zMQg;KQ!u@+a!L5+p>9=gDzls5NX598qj)&`50nR>*~qtpui6hjxS6`gA5%3jLZ2eg zWacYy)iF&?ZVSE97}>!IC69_u=t9oyt6$gi@-eYNRV>eyM%ev9N8EZa#F>4 zVi(M-2;6oJJ&Y`VF|?k_C+{qCUi6k?1MStCivVKq-knX1 z#o}kKD!;%Fh*tt*yXx}XuI$|^)!X7#;@I(%?i(+fP+pGj>zIEy6{PRH~FL)(Rhxut=aO3zlOF)kP%Li;_jwpcue>H^CZ-sfMB(*~(S@1d<~WLNZmfk6mW)5jj~ixQ5fKctEHa))V2=)>d#1 z_?rN@Gkr&DKFH2!pWah8^Cl@cxZh--Pi^s3phQJ6H#KC0e=)qp{p}9A2P)e3WN~50 zEEgR|ITmW0!1t@U$ObwNGzol>6L)ox&rK&as;d({;+7BL5n%A7~aJp4tO5KW{1p@40`a?zRRJ8n2i%)cL6Bf7Txn?3kSoLv3izlrQsW~m)r?lfW}5ay(s2Gb%s)( z7RKy*J~XP<>ornBBk=Snj#U}>uV_W}QKH4g#vqh(y&pj!#EJmR47a)eZ2XG%%SyhN zP?Ug3nukOyK}FN(xa3q`fv1#QCEO*WwV?=gJ>8cO)uLLK;MTppe@rVCd%@H*jYVu! zc$81&)s8^#Nt|Pcz}z3eoa%a_b3ZaP4xcND*kbK^HS-QnqGN3~I;uzJQ!5|lR!lP< z?d!><=VBYtCAZG=1Xm!@|N1xI^{%z?k{bpG`IKxlBaSLNzx^3 zkTitJwXr!R7_SqiSc$4Oq=z~=mUI_bA_~je)Av#Nk)gVv4_^$w5C4leE)pM-vy-?( zDIt4mY6B!G_P=y`Ja>EibI54P2t%+Kq<;&NGWTio3!ucQumQDy;s1X*D~{jiQrKH{ z8mo1`u{A62YH+i|?+qv2kvEi3GYVQt^vuJ#7r-beWOd+Vt*Rpe-V^bavIEil`x2Bc zlKl54+XXUf$i~NIBX{xo_2tpW=)N(Zy!7uqwXWZz=3)t1Yn#v|yaDN5 z=2x7b>fv#Vh+OHA8+(w+hldhE-*u=mFNb{+H(t?T$Tt4e;+Qhm6u7Q}Sx6-CXeDTP zfcL&gzc6}ynmq?AhKERzzfs$bPi0e}^!27(bt|bfuF+Kd0M6vT4Lxv&dDf`^1Dtn3 zb&3FFcN7(>PcN5~fBVk*TF*Qh;lpyQI2}pRbqkt6I#P{dhZ^zqe;skPe^CwuC;JjTOWOYcHc;mOl(b*kF(Cjt z;93rQ_P!wME-sU=T6pbD!=op}XLX700ui=-v(RTK^k zZoT9I!G_{h^9^4PH=8aVl<8^Sf@HSFjNvbz+M_(2_8F+`7HNl-Bs!YE67_wa#wUX2 zqeqK_=Jix&ra{>bgb5gcC^j}%!V?V8NLOPQg*rOo*r8%3+G)EyJ+gH8^si!DP?LK> zWde%EFcd7XO>gbBqK0F7x3DsV`**&B8)>XEsn|1cg7J6;#?JSyAaX!j>(yF#-*6uw zyxsnw$7Ja9(jdckD916!$ylZ6ek4;#3LNktrqzp^Ske}=hXMcZ?4ST zB_MLv*x30Lqu_WM0}r#uML+gtr%~a3>_31^OQYq~LgO$@zI!Dpxj^L#(PHL#O8XOS zE%D?C)fi#3j#cS|!Gf=SWvB&^*tKa)MgN$V+a?%j7{Y(>5IEj!fbhkw}1{ z`gAw+@If5yI6fy?lC|ndb-Rr^O)Os`FS_jmRM{T@!u}Xs-8TY*j($OKzCeV>Sxbc% zP+YybQG1AI=i>%pq}Xbi+E*4xE^q(O-Hd-8Lw2|_D8j~JPj$2`m$B%C|hj7Jj6Df{AL)DUQ zWuzfpF=*%7S1!LBmI@*T9mH4+@;68DrtB7=+J6v)Lxo$O33Dz=!x;B=h70!Bh;P`0 zPYca;%=G2c$hsMDwzJs#uLKmuu=<>z0o7iTxif-!?`JkpkKRrxI85|Qdo<9Bm~U8ZFQ z?@@z=9>t=A-pnG;Ca=%{|FBU-th6OKx9pC0wWmv+ZN=lN9@b395A0QFH5#z9$BHKZ zV*G?Icru&rS6#OUWM=_xZDp|fsgb*C+s~w31dN;2Swt_f_shO<=*pBCuNT(En+D(- zyJm-=<8GyVFdjYj6D}QJgjGT}G8{WPN^J* z&L%l`H#<_Y31c6dhM$j1V<)VjHC5j(BqTGEDsFCYGpoeN6z4N0>Lb&4s>QLm=53F^ zHS>dD6s1-~>Q<}lL9oWaifRhgnBNQ5X+m#rKzHBc=U2Nh<;N7UbJ=Uhh0>Br-cYsh znd$Yf6!UYg1}=$pR`idD25sQHndCvOXNvxe82;xVD*gv|hhU0{|Mo-uzsXD0j*~$^ zkezB}Sn=(>HK-W6t+iA##{%mo?=dYv_345*;Gz;{=E}2G?e_SDiivFNqBBzDNY^Lw zvz1keaEe#Ld-@GY2iAs&B%EDS(OsTp$pc*{0}~fBZWj-l&LNa*kD!u$Z(*|V;0NtH zwcW3rL{FgUqx3e@Ky<`o6e~Ansi&UPxYxt13}o)8yfx01f{o2yXdBqvw|vw}1VpFq zIA7FVY^0q8;#92R6gUztC{Oc(m*Ra%pQXyqY7Vlc{*x1#Jby2`d&l>rsEAqb(R9|P z*rbc$)VE<$SUkOJlgMiic90V~BO1zNe^ToEej4%bD=J?Q?x*qP^O)l<(-B7-MMW4R z1|v`Mrj33#r0;$kPkUcT;?XF(qp9+mk&;<+{t|Sgbr-&z$SgC+x&(|>`J7gPFtG0^ z&90425$O9SHbaWvH1G8g{)wUcFEq;^geDhZu)VBG-@Nuh5RuTZQ}M;6Hlc7?Ks;L+ zK1eF!sBTcrNXc2MpVKZ*lyhL)ft-vJNM*^)ETDDQO5NQ(c|iNBr5AZwv9%KE@o!VY)ffu{ZwG-32qJW@UNYBoH0iWlMKssMVX>n3WVN`wgS6|v( zPQn^-=#zwZ;>Q{rQJ9K42{mVEqLYgL3criLo{9yG-LJs9SAfqxYP2yC?$ zA;Xd4wNSb7h=*pQL1eyV(Y5hKMr`SW`fR0U%uLKE^%@MG-Tkk*x5T-QuI$SzqZcg4 zhw@fXI&ou_GHuntM^feM@(fCZsU)2937h3ktMHRQ>iFfXu#mgMcck~e?A~rP(3-vV zteL*7bh?qvyXEy7Ejk$P8;Yd3kyO5gw2II$P;-Ch0Badj~ZfsV(a)A`o#?^tNw##Ofq8aeb>{xIydw#@VDX{E&HNoH^Ni>iCh@ zVvcRkBQ2rLK;2&yJ94tMzKeHpzwTA+{T6`bs!VRNsqu%D3i0w}gg6sBYoNa8-IS+F zp8bgEUZ|M3Y%z?CMw-5Tv<@|xJC%7&%nw5ED^}0pVz^#GI7QLkC={Q@-E{vdJPBKZ zb%pX3_DqB;ftJXaTrN&2)i-#QdVmx5Ptpu2;IfL&Y!8pBWPdjyA@NQDV@z{z8k=+J zE2ILKtg*^g6x7W$T;?^+>JtQ2dK@+WOq{Y_AVTTSMnUNT*xkAfBsWt1!3X8^h6rrpG)d~`G{z-ka zefzE=%>gqWI1m)PKr4#d_G5f+NO5c4+L~A2;gBBKnP#j{QB!L)5w5X-Lji0i{NC;- zsnea(cf5}%&iCaEJ--#ZC~$4_G^iu_d8;n3@CfIo0`foGN&{=OUD^aE&Bt46yCRcQ&8HkTv)ns*&wV9V^C$g6l z*(a`iLhnYlx-|l8g2MoCzaK^%-Yh;o-k&r#rx^Y8j1gj<`L>Im_xnhZ&o6qc+`3pC zeQUt1+0@#2qcr)EPgPSRLR|Q`qba&aNtAKOu>nJ|9l0B|Wg5n|1FxJ&0M3o5MkOkh zM&)*{I)ctL_Vpp__~cMj-kqbWsp0G~`>0Pocg`CnCMMzo^&nb5HmP-NH02&Ii|oDP zyk9PLQgGy9z=+)+2OkAL6Hf${Zi+cly8CysGZ_245&r`q>1?&@`H6X1i45;AbXf}K zlgVCJ$mSg29$z8S%aU2DAD`oPVf+4l3}ZL4+-;}u%&Ob&|9JdyxaobOxeX{s%{2yF4Zp@L{?uy7kzOkq}q?QgFv(~6!2)KGto$Xchnf(U=tyR&R$$g#BM38-SG6; zdl6iY@=t=nr>?!Y%ot4k!bmcJS5CPBPp3y$l^S)8{`)I5_3>08y{b|E2oDS!^R_Y> zXuGlvz zDxT<4nT~h<2M&J*=e{zKzB9Dg?Is!;dzu5yDV+pe)unzYKTb z!U6{PBW3(_eQC~%H^@@qipg}`31LAy+3|Hjzi~JU!%%aIhnM2+l+hlwpyaW~dG`1a%ID?xXD{GFKb8Mb$^JeBe{ znia;nZr-NtNsl@6u@9DlCJ*B7s>K&<>Gx_C>5c;7TijfexVs@;xv1SLIgy^x{4=cm zsrAU{UMTK**@XkS2g=$G=vS8b2wNbWt5tyJ6U7s5&{AT6PI%O`r3mlZc0}Dm#yR2`toSXx+dl8>+!)9`T8^A zPm~@>0vD1v-*PNFkI|SV9ygxA-+8ClEW3pBMdWeON(-XjQ0RAi*mw zNdm-C1{G7~^rkzk2nOEwC;g>0CK|-6;7o?~5b9KD(6UX(iH=Lb&pl-LbzP?E8|5RN z^36BVsT{r`8W@=}LuV+HOXl1PF@)KQCn*hxd$)6(o1W!OHZ6cC$vci{g&HF4)Qn@P<-*%dwJM2PuTEV_AMQ%8B}i?H#T#3rds!{D;GCKA zO(yVOP%3@G{Dlndvq%*AL*{m!Y7A65t`j{y8E4BeRNXvqJwKJX6SVS=^(Sf}`m zq{ZuwtJo|4!RPAdDV92;;JLDPNP=zBZJ>SV{u7ZFQ(uVMxhk=092)DG(S*W9h3Ltn zmunl~4ygvYs)(C~0(+7)w=?n!s^Z~hMuT~VTy0l_?H}dEo zn`b``a(&o8WZv9+beiuKjNA)|ti>Bgl6|$)I=*aG#irrYFf3#@up*|2q*PP5<_>dgfREC7|#f9!)&NseA&ZXd3Ne;g=R9ZOS=Wh zeEJ7y9vw;g)%rktzZak4OWLfR3EWe& z&gMgLh-JhZ@hFsw;mG`SsEgu7%3IMAj>BUmyNBSXRSQGoiLtlzYOsQ6AIs5B$gf85h9+S@=Je4`QwW literal 0 HcmV?d00001 From dcbe05f8dc03ca6019f6a87d697dfc63982d50a3 Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Mon, 17 Jun 2019 10:24:54 +0200 Subject: [PATCH 03/17] Create 0006-linear-clash.md --- content/blog/0006-linear-clash.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 content/blog/0006-linear-clash.md diff --git a/content/blog/0006-linear-clash.md b/content/blog/0006-linear-clash.md new file mode 100644 index 0000000..ea0634e --- /dev/null +++ b/content/blog/0006-linear-clash.md @@ -0,0 +1,18 @@ +--- +title: "Clash's case for linear types in Haskell" +date: "2019-06-11" +description: "What it says on the tin" +disable_comments: false +author: "martijnbastiaan" +authorbox: true # Optional, enable authorbox for specific post +summary: Linear types are hopefully to hit GHC imminent, here we present Clash's use case for them. +toc: false +mathjax: false +--- + +I'm writing this post on the train on my way back from an amazing ZuriHac 2019, where I got to meet a lot of new people, many of them really excited about Clash! +I also got to talk with some about the linear types feature that will hopefully hit GHC HEAD very soon. +There were some thoughts floating around in my head on how to use linear types (not "original" thoughts, but I'll get to that later) for Clash, but wasn't really sure how the linear arrows approach would actually fit. +But thanks to the helpful explanations of Araud, Csongor, Krzysztof, and Simon, I finally understand how linear arrows work, and _why_ they would work for Clash! +Getting back to the 'not original thoughts', it was actually the work of [Dan Ghica](http://www.cs.bham.ac.uk/~drg/papers.html) on "Geometry of Synthesis (GoS)" that introduced me to the idea of how linear types (GoS actually uses affine types) and hardware fit together. + From 8498bdcb8f5b7ed8887dc0d4ba18ca2efdf7b4f6 Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Mon, 17 Jun 2019 11:31:52 +0200 Subject: [PATCH 04/17] Update 0006-linear-clash.md --- content/blog/0006-linear-clash.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/blog/0006-linear-clash.md b/content/blog/0006-linear-clash.md index ea0634e..f89ee1e 100644 --- a/content/blog/0006-linear-clash.md +++ b/content/blog/0006-linear-clash.md @@ -14,5 +14,5 @@ I'm writing this post on the train on my way back from an amazing ZuriHac 2019, I also got to talk with some about the linear types feature that will hopefully hit GHC HEAD very soon. There were some thoughts floating around in my head on how to use linear types (not "original" thoughts, but I'll get to that later) for Clash, but wasn't really sure how the linear arrows approach would actually fit. But thanks to the helpful explanations of Araud, Csongor, Krzysztof, and Simon, I finally understand how linear arrows work, and _why_ they would work for Clash! -Getting back to the 'not original thoughts', it was actually the work of [Dan Ghica](http://www.cs.bham.ac.uk/~drg/papers.html) on "Geometry of Synthesis (GoS)" that introduced me to the idea of how linear types (GoS actually uses affine types) and hardware fit together. +Getting back to the 'not original thoughts', it was actually the work of [Dan Ghica](http://www.cs.bham.ac.uk/~drg/papers.html) on "Geometry of Synthesis (GoS)" that introduced me to the idea of how linear types (GoS actually uses affine types) and hardware fit together, and so many of the concepts in this blog post can be found in the GoS papers ([1](http://www.cs.bham.ac.uk/~drg/papers/popl07x.pdf), [2](http://www.cs.bham.ac.uk/~drg/papers/mfps10.pdf), [3](http://www.cs.bham.ac.uk/~drg/papers/popl11.pdf), [4](http://www.cs.bham.ac.uk/~drg/papers/icfp11.pdf), [5](http://www.cs.bham.ac.uk/~drg/papers/lics09tut.pdf), [6](http://www.cs.bham.ac.uk/~drg/papers/memocode11.pdf)) in one shape or form. From cefca66df79c63a3347a3c04cc7ba4b64350882d Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Mon, 17 Jun 2019 12:02:50 +0200 Subject: [PATCH 05/17] Update 0006-linear-clash.md --- content/blog/0006-linear-clash.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/content/blog/0006-linear-clash.md b/content/blog/0006-linear-clash.md index f89ee1e..495921e 100644 --- a/content/blog/0006-linear-clash.md +++ b/content/blog/0006-linear-clash.md @@ -3,7 +3,7 @@ title: "Clash's case for linear types in Haskell" date: "2019-06-11" description: "What it says on the tin" disable_comments: false -author: "martijnbastiaan" +author: "christiaanbaaij" authorbox: true # Optional, enable authorbox for specific post summary: Linear types are hopefully to hit GHC imminent, here we present Clash's use case for them. toc: false @@ -16,3 +16,29 @@ There were some thoughts floating around in my head on how to use linear types ( But thanks to the helpful explanations of Araud, Csongor, Krzysztof, and Simon, I finally understand how linear arrows work, and _why_ they would work for Clash! Getting back to the 'not original thoughts', it was actually the work of [Dan Ghica](http://www.cs.bham.ac.uk/~drg/papers.html) on "Geometry of Synthesis (GoS)" that introduced me to the idea of how linear types (GoS actually uses affine types) and hardware fit together, and so many of the concepts in this blog post can be found in the GoS papers ([1](http://www.cs.bham.ac.uk/~drg/papers/popl07x.pdf), [2](http://www.cs.bham.ac.uk/~drg/papers/mfps10.pdf), [3](http://www.cs.bham.ac.uk/~drg/papers/popl11.pdf), [4](http://www.cs.bham.ac.uk/~drg/papers/icfp11.pdf), [5](http://www.cs.bham.ac.uk/~drg/papers/lics09tut.pdf), [6](http://www.cs.bham.ac.uk/~drg/papers/memocode11.pdf)) in one shape or form. +# Synthesis of higher-order functions + +Given a function: + +{{< highlight haskell >}} +f :: Int32 -> Int32 -> Bool +{{< / highlight >}} + +Clash will convert this to a circuit with two 32-bit input ports, corresponding to the two `Int32` arguments, and a 1-bit output port, corresponding to the `Bool` result. +That is, Clash will create a circuit from a function where the function's arguments are transformed to input ports, and the result of the function is mapped to an output port. +And then when a function is called, the circuits corresponding to the applied arguments are connected to the input ports, and the output port is connected to the circuits corresponding to the expressions using the result of the (fully) applied circuit. + +In many situations this is a straightforwared prcoess, but what happens when one of the arguments has a function type? + +{{< highlight haskell >}} +f :: (Int32 -> Int32) -> Int32 -> Bool +f h y = (h y) < 10 + +g :: Int32 -> Bool +g x = f k x + +k :: Int32 -> Int32 +{{< / highlight >}} + +How many bits are needed for a port of type `(Int32 -> Int32)`? How would the input port `y` corresponding to hook up to the input port corresponding to `h`? How, inside `g`, do we hook up the input ports of `k` to the input port to the input port `h`? +Clearly this idea of mapping arguments to input ports, and results to output ports, doesn't work when our arguments have a function type. From 3b3a43437f7c2bca9265204c8c2a1141775e4e46 Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Mon, 17 Jun 2019 12:26:34 +0200 Subject: [PATCH 06/17] Update 0006-linear-clash.md --- content/blog/0006-linear-clash.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/content/blog/0006-linear-clash.md b/content/blog/0006-linear-clash.md index 495921e..fc20a1e 100644 --- a/content/blog/0006-linear-clash.md +++ b/content/blog/0006-linear-clash.md @@ -34,11 +34,25 @@ In many situations this is a straightforwared prcoess, but what happens when one f :: (Int32 -> Int32) -> Int32 -> Bool f h y = (h y) < 10 -g :: Int32 -> Bool -g x = f k x - k :: Int32 -> Int32 + +topEntity :: Int32 -> Bool +topEntity x = f k x {{< / highlight >}} How many bits are needed for a port of type `(Int32 -> Int32)`? How would the input port `y` corresponding to hook up to the input port corresponding to `h`? How, inside `g`, do we hook up the input ports of `k` to the input port to the input port `h`? -Clearly this idea of mapping arguments to input ports, and results to output ports, doesn't work when our arguments have a function type. +Clearly this idea of mapping arguments to input ports, and results to output ports, doesn't work when our arguments have a function type. So how does Clash handle this? Well, before converting the expressions to a circuit, uses a process called specialisation to transform the above code to: + +{{< highlight haskell >}} +fK :: Int32 -> Bool +fK y = (k y) < 10 + +k :: Int32 -> Int32 + +topEntity :: Int32 -> Bool +topEntity x = fK x +{{< / highlight >}} + +resulting in a collection of functions where none of them have an argument with a function type; and so the idea of mapping arguments to input ports, and results to output works, will work again. +This specialisation process will always succeed as long as `topEntity` doesn't have any arguments with a function type. +And in the case that `topEntity` does have arguments with a function type, Clash gives up immediately and reports to the user that their code cannot be translated into a circuit. From 5b0c84af25c791e668cc23db77572e611649e267 Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Mon, 17 Jun 2019 12:53:01 +0200 Subject: [PATCH 07/17] Update 0006-linear-clash.md --- content/blog/0006-linear-clash.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/content/blog/0006-linear-clash.md b/content/blog/0006-linear-clash.md index fc20a1e..7121c3e 100644 --- a/content/blog/0006-linear-clash.md +++ b/content/blog/0006-linear-clash.md @@ -55,4 +55,13 @@ topEntity x = fK x resulting in a collection of functions where none of them have an argument with a function type; and so the idea of mapping arguments to input ports, and results to output works, will work again. This specialisation process will always succeed as long as `topEntity` doesn't have any arguments with a function type. -And in the case that `topEntity` does have arguments with a function type, Clash gives up immediately and reports to the user that their code cannot be translated into a circuit. +And in the case that `topEntity` does have arguments with a function type, Clash gives up immediately and reports to the user that their code cannot be translated into a circuit. + +# Synchronisation and the case for a higher-order top-level functions +You might argue that a first-order top-level function (`topEntity`) is a sensible restriction, after all, it's kind of the "entry point" into your entire circuit (much like `main :: IO ()` in regular Haskell program). +So what use would we have for a higher-order `topEnity`? + +One such case is when your circuit is communicating with peripherals that have an explicit synchronisation, whether it be an _acknowledge_, _ready_, or _wait_ signal, and both in case your circuit is producing that synchronisation signal or consuming that synchronistation signal. +In these cases, when you're producing data, then this data is part of the result of your `topEntity`, corresponding to an output port, and the synchronistation channel becomes an argument, corresponding to an input. +When you're consuming data, then this data becomes an argument, corresponding to an output port, and the synchronistation channel becomes part of the result, corresponding to an output port. +Now imagine that your circuit is communicating with six peripherals. From 8ff919e2562de72ae36dd2a299c27337f1bdc499 Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Mon, 17 Jun 2019 13:24:25 +0200 Subject: [PATCH 08/17] Update 0006-linear-clash.md --- content/blog/0006-linear-clash.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/content/blog/0006-linear-clash.md b/content/blog/0006-linear-clash.md index 7121c3e..4032b08 100644 --- a/content/blog/0006-linear-clash.md +++ b/content/blog/0006-linear-clash.md @@ -65,3 +65,28 @@ One such case is when your circuit is communicating with peripherals that have a In these cases, when you're producing data, then this data is part of the result of your `topEntity`, corresponding to an output port, and the synchronistation channel becomes an argument, corresponding to an input. When you're consuming data, then this data becomes an argument, corresponding to an output port, and the synchronistation channel becomes part of the result, corresponding to an output port. Now imagine that your circuit is communicating with six peripherals. +With a first-order restriction on your `topEntity`, the only way to implement this is to have something like: + +{{< highlight haskell >}} +topEntity :: DataIn1 -> DataIn2 -> SyncIn3 -> DataIn4 -> (SyncOut1, SyncOut2, DataOut3, SyncIn4) +topEntity d1 d2 s3 d4 = (s1, s2, d3, s4) + where + ... +{{< / highlight >}} + +where the data and synchronisation part of a channel become syntactically seperated, and you'll quickly use the overview of what's going on. +It becomes worse when you get to protocols like AXI4, where you're the consumer of some data, and the producer of some other data. + +The interface just becomes so much nice if you could simply write: + +{{< highlight haskell >}} +type DataConsumer1 = DataIn1 -> SyncOut1 +type DataConsumer2 = DataIn2 -> SyncOut2 +type DataProducer3 = SyncIn3 -> DataOut3 +type DataConsumer4 = DataIn4 -> SyncOut4 + +topEntity :: DataConsumer1 -> DataConsumer2 -> DataProducer3 -> DataConsumer4 +topEntity c1 c2 p3 = c4 + where + ... +{{< / highlight >}} From 6bf857e79f8dd15655c7bfc6daf17df3d51ecee9 Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Mon, 17 Jun 2019 13:36:45 +0200 Subject: [PATCH 09/17] Update 0006-linear-clash.md --- content/blog/0006-linear-clash.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/content/blog/0006-linear-clash.md b/content/blog/0006-linear-clash.md index 4032b08..04f1ea9 100644 --- a/content/blog/0006-linear-clash.md +++ b/content/blog/0006-linear-clash.md @@ -64,11 +64,11 @@ So what use would we have for a higher-order `topEnity`? One such case is when your circuit is communicating with peripherals that have an explicit synchronisation, whether it be an _acknowledge_, _ready_, or _wait_ signal, and both in case your circuit is producing that synchronisation signal or consuming that synchronistation signal. In these cases, when you're producing data, then this data is part of the result of your `topEntity`, corresponding to an output port, and the synchronistation channel becomes an argument, corresponding to an input. When you're consuming data, then this data becomes an argument, corresponding to an output port, and the synchronistation channel becomes part of the result, corresponding to an output port. -Now imagine that your circuit is communicating with six peripherals. +Now imagine that your circuit is communicating with four peripherals, with 3 peripherals producing data, and 1 consuming data. With a first-order restriction on your `topEntity`, the only way to implement this is to have something like: {{< highlight haskell >}} -topEntity :: DataIn1 -> DataIn2 -> SyncIn3 -> DataIn4 -> (SyncOut1, SyncOut2, DataOut3, SyncIn4) +topEntity :: Data1 -> Data2 -> Sync3 -> Data4 -> (Sync1, Sync2, Data3, Sync4) topEntity d1 d2 s3 d4 = (s1, s2, d3, s4) where ... @@ -77,16 +77,18 @@ topEntity d1 d2 s3 d4 = (s1, s2, d3, s4) where the data and synchronisation part of a channel become syntactically seperated, and you'll quickly use the overview of what's going on. It becomes worse when you get to protocols like AXI4, where you're the consumer of some data, and the producer of some other data. -The interface just becomes so much nice if you could simply write: +The interface just becomes so much nicer if you could simply write: {{< highlight haskell >}} -type DataConsumer1 = DataIn1 -> SyncOut1 -type DataConsumer2 = DataIn2 -> SyncOut2 -type DataProducer3 = SyncIn3 -> DataOut3 -type DataConsumer4 = DataIn4 -> SyncOut4 +type DataProducer1 = Sync1 -> Data1 +type DataProducer2 = Sync2 -> Data2 +type DataConsumer3 = Data3 -> Sync3 +type DataProducer4 = Sync4 -> Data4 -topEntity :: DataConsumer1 -> DataConsumer2 -> DataProducer3 -> DataConsumer4 +topEntity :: DataProducer1 -. DataProducer2 -. DataConsumer3 -. DataConsumer4 topEntity c1 c2 p3 = c4 where ... {{< / highlight >}} + +Also note that it's impossible to convert between the two, and so we really need linear types for the above API to work safely. From cd00a5d4592bb5f18d1fd5e73f0024ba36c76531 Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Mon, 17 Jun 2019 14:27:19 +0200 Subject: [PATCH 10/17] Update 0006-linear-clash.md --- content/blog/0006-linear-clash.md | 36 ++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/content/blog/0006-linear-clash.md b/content/blog/0006-linear-clash.md index 04f1ea9..7d09cb3 100644 --- a/content/blog/0006-linear-clash.md +++ b/content/blog/0006-linear-clash.md @@ -10,6 +10,8 @@ toc: false mathjax: false --- +__TL;DR Consuming a function linearly means consuming the function's argument linearly, which at the circuit-level means that the output port of a higher-order argument is only driven by a single source. This means we need linear arrows to correctly translate non-duplicable functions, e.g. the higher-order arguments of the very top of our function hierarcy.__ + I'm writing this post on the train on my way back from an amazing ZuriHac 2019, where I got to meet a lot of new people, many of them really excited about Clash! I also got to talk with some about the linear types feature that will hopefully hit GHC HEAD very soon. There were some thoughts floating around in my head on how to use linear types (not "original" thoughts, but I'll get to that later) for Clash, but wasn't really sure how the linear arrows approach would actually fit. @@ -57,7 +59,39 @@ resulting in a collection of functions where none of them have an argument with This specialisation process will always succeed as long as `topEntity` doesn't have any arguments with a function type. And in the case that `topEntity` does have arguments with a function type, Clash gives up immediately and reports to the user that their code cannot be translated into a circuit. -# Synchronisation and the case for a higher-order top-level functions +# Synthesis of higher order functions, take 2 +So what if we really wanted a higher-order `topEntity`, how could we then proceed? +Now the following concept is exactly described in the Geometry of Synthesis papers, for any argument with a function type: + +* The function arguments become output ports, +* and the function result becomes an output port, +* and if any of the arguments are themself higher-order then the "polarity" inside of them will be switched again. + +So in: + +{{< highlight haskell >}} +f :: (Int32 -> Int32) -> Int32 -> Bool +f h y = (h y) < 10 + +k :: Int32 -> Int32 + +topEntity :: Int32 -> Bool +topEntity x = f k x +{{< / highlight >}} + +the component for `f` would get: + +* an additional `Int32` input port corresponding to the result of the `h` argument, +* and an additional `Int32` output port corresponding to the argument of `h`. + +Inside the component for `f` we would then: + +* connect the input port corresponding to `y` to the output port corresponding to `h`s argument, +* and connect the input port corresponding to `h`s result to the left input of the `<` component. + +Inside `topEntity` + +# Synchronisation and the case for higher-order top-level functions You might argue that a first-order top-level function (`topEntity`) is a sensible restriction, after all, it's kind of the "entry point" into your entire circuit (much like `main :: IO ()` in regular Haskell program). So what use would we have for a higher-order `topEnity`? From 905ed3ef3f27a721db6feb2b5f1e1068f70b7284 Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Mon, 17 Jun 2019 14:51:38 +0200 Subject: [PATCH 11/17] Update 0006-linear-clash.md --- content/blog/0006-linear-clash.md | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/content/blog/0006-linear-clash.md b/content/blog/0006-linear-clash.md index 7d09cb3..bc0fecc 100644 --- a/content/blog/0006-linear-clash.md +++ b/content/blog/0006-linear-clash.md @@ -10,7 +10,7 @@ toc: false mathjax: false --- -__TL;DR Consuming a function linearly means consuming the function's argument linearly, which at the circuit-level means that the output port of a higher-order argument is only driven by a single source. This means we need linear arrows to correctly translate non-duplicable functions, e.g. the higher-order arguments of the very top of our function hierarcy.__ +__TL;DR Consuming a function linearly means consuming the function's argument linearly, which in a circuit context means that the output port of a higher-order argument is only driven/written by a single source. This means we need linear arrows to correctly translate non-duplicable functions, e.g. higher-order arguments corresponding to components peripheral to our circuit.__ I'm writing this post on the train on my way back from an amazing ZuriHac 2019, where I got to meet a lot of new people, many of them really excited about Clash! I also got to talk with some about the linear types feature that will hopefully hit GHC HEAD very soon. @@ -89,7 +89,28 @@ Inside the component for `f` we would then: * connect the input port corresponding to `y` to the output port corresponding to `h`s argument, * and connect the input port corresponding to `h`s result to the left input of the `<` component. -Inside `topEntity` +Inside `topEntity`, we would then: + +* Connect the input port of `k` to the output port of `f` that corresponds to the argument of `h`, +* and connect the ouptput port of `k` to the input port of `f` that corresponds to the result of `h`. + +_TODO: create a picture making the above more intuiative._ + +# Consuming functions linearly + +Now let's say we change our definition of `f` to: + +{{< highlight haskell >}} +f :: (Int32 -> Int32) -> Int32 -> Int -> Bool +f h x y = (h x + h y) < 10 +{{< / highlight >}} + +i.e. apply the function `h` twice to different arguments. +If we would keep the same translation, then the input port corresponding the the result of `h` would be connected to the input ports of the `+` component. +There are no issues here, a source can drive/write multiple sinks. +The catastropic issue is that the output port corresponding to the argument of `h` is now being driven/written by the input ports corresponding to `x` and `y`: a sink should only be driven/written by a single source! + +_TODO: create a picture making the above more intuiative._ # Synchronisation and the case for higher-order top-level functions You might argue that a first-order top-level function (`topEntity`) is a sensible restriction, after all, it's kind of the "entry point" into your entire circuit (much like `main :: IO ()` in regular Haskell program). From 51e6b7b3eca9065104ef046de37b38ed413551e1 Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Mon, 17 Jun 2019 15:37:21 +0200 Subject: [PATCH 12/17] Update 0006-linear-clash.md --- content/blog/0006-linear-clash.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/blog/0006-linear-clash.md b/content/blog/0006-linear-clash.md index bc0fecc..3753ff9 100644 --- a/content/blog/0006-linear-clash.md +++ b/content/blog/0006-linear-clash.md @@ -10,7 +10,7 @@ toc: false mathjax: false --- -__TL;DR Consuming a function linearly means consuming the function's argument linearly, which in a circuit context means that the output port of a higher-order argument is only driven/written by a single source. This means we need linear arrows to correctly translate non-duplicable functions, e.g. higher-order arguments corresponding to components peripheral to our circuit.__ +__TL;DR Consuming a function linearly means consuming the function's argument linearly, which in a circuit context means that the output port of a higher-order argument is only driven/written by a single source. This means we need linear arrows to correctly translate non-duplicable functions, e.g. higher-order arguments corresponding to components peripheral to the circuit.__ I'm writing this post on the train on my way back from an amazing ZuriHac 2019, where I got to meet a lot of new people, many of them really excited about Clash! I also got to talk with some about the linear types feature that will hopefully hit GHC HEAD very soon. From cc889b861a9dd5414c177637250a176cb0893410 Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Mon, 17 Jun 2019 15:50:08 +0200 Subject: [PATCH 13/17] Update 0006-linear-clash.md --- content/blog/0006-linear-clash.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/content/blog/0006-linear-clash.md b/content/blog/0006-linear-clash.md index 3753ff9..a506306 100644 --- a/content/blog/0006-linear-clash.md +++ b/content/blog/0006-linear-clash.md @@ -112,6 +112,11 @@ The catastropic issue is that the output port corresponding to the argument of ` _TODO: create a picture making the above more intuiative._ +There are two options here: + +1. Duplicate the output (and input) ports of the `h` argument so that `x` and `y` can be connected to these outputs seperately; this behaviour basically corresponds to the specialisation transformation Clash applies already. +2. Use linear arrows + # Synchronisation and the case for higher-order top-level functions You might argue that a first-order top-level function (`topEntity`) is a sensible restriction, after all, it's kind of the "entry point" into your entire circuit (much like `main :: IO ()` in regular Haskell program). So what use would we have for a higher-order `topEnity`? From 4ab4fe05c545c5f0100678bb619d77a9873365a4 Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Mon, 17 Jun 2019 15:55:59 +0200 Subject: [PATCH 14/17] Update 0006-linear-clash.md --- content/blog/0006-linear-clash.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/blog/0006-linear-clash.md b/content/blog/0006-linear-clash.md index a506306..bfddc1f 100644 --- a/content/blog/0006-linear-clash.md +++ b/content/blog/0006-linear-clash.md @@ -10,7 +10,7 @@ toc: false mathjax: false --- -__TL;DR Consuming a function linearly means consuming the function's argument linearly, which in a circuit context means that the output port of a higher-order argument is only driven/written by a single source. This means we need linear arrows to correctly translate non-duplicable functions, e.g. higher-order arguments corresponding to components peripheral to the circuit.__ +__TL;DR What does it mean for a function to be used linearly? It means that it's argument will be used linearly. Somewhat surprisingly, in a circuit context it means that the output port of a higher-order argument is only driven by a single source. This means we need linear arrows to correctly translate non-duplicable functions, e.g. higher-order arguments corresponding to components peripheral to the circuit.__ I'm writing this post on the train on my way back from an amazing ZuriHac 2019, where I got to meet a lot of new people, many of them really excited about Clash! I also got to talk with some about the linear types feature that will hopefully hit GHC HEAD very soon. From bf369d3eac083a431fa2b7eaa332a1635489082b Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Mon, 17 Jun 2019 16:01:53 +0200 Subject: [PATCH 15/17] Update 0006-linear-clash.md --- content/blog/0006-linear-clash.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/blog/0006-linear-clash.md b/content/blog/0006-linear-clash.md index bfddc1f..0361ae9 100644 --- a/content/blog/0006-linear-clash.md +++ b/content/blog/0006-linear-clash.md @@ -10,7 +10,7 @@ toc: false mathjax: false --- -__TL;DR What does it mean for a function to be used linearly? It means that it's argument will be used linearly. Somewhat surprisingly, in a circuit context it means that the output port of a higher-order argument is only driven by a single source. This means we need linear arrows to correctly translate non-duplicable functions, e.g. higher-order arguments corresponding to components peripheral to the circuit.__ +__TL;DR What does it mean for a function to be used linearly? It means that it's _argument_ will be used linearly. Somewhat surprisingly, in a circuit context it means that the _output port_ of a higher-order argument is only driven by a single source. This means we need linear arrows to correctly translate non-duplicable functions, e.g. higher-order arguments corresponding to components peripheral to the circuit.__ I'm writing this post on the train on my way back from an amazing ZuriHac 2019, where I got to meet a lot of new people, many of them really excited about Clash! I also got to talk with some about the linear types feature that will hopefully hit GHC HEAD very soon. @@ -30,7 +30,7 @@ Clash will convert this to a circuit with two 32-bit input ports, corresponding That is, Clash will create a circuit from a function where the function's arguments are transformed to input ports, and the result of the function is mapped to an output port. And then when a function is called, the circuits corresponding to the applied arguments are connected to the input ports, and the output port is connected to the circuits corresponding to the expressions using the result of the (fully) applied circuit. -In many situations this is a straightforwared prcoess, but what happens when one of the arguments has a function type? +In many situations this is a straightforward process, but what happens when one of the arguments has a function type? {{< highlight haskell >}} f :: (Int32 -> Int32) -> Int32 -> Bool @@ -64,7 +64,7 @@ So what if we really wanted a higher-order `topEntity`, how could we then procee Now the following concept is exactly described in the Geometry of Synthesis papers, for any argument with a function type: * The function arguments become output ports, -* and the function result becomes an output port, +* and the function result becomes an input port, * and if any of the arguments are themself higher-order then the "polarity" inside of them will be switched again. So in: From d04c69d587526f50276b752204e317e76da6addc Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Mon, 17 Jun 2019 16:08:23 +0200 Subject: [PATCH 16/17] Update 0006-linear-clash.md --- content/blog/0006-linear-clash.md | 34 +++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/content/blog/0006-linear-clash.md b/content/blog/0006-linear-clash.md index 0361ae9..400b2d4 100644 --- a/content/blog/0006-linear-clash.md +++ b/content/blog/0006-linear-clash.md @@ -10,7 +10,7 @@ toc: false mathjax: false --- -__TL;DR What does it mean for a function to be used linearly? It means that it's _argument_ will be used linearly. Somewhat surprisingly, in a circuit context it means that the _output port_ of a higher-order argument is only driven by a single source. This means we need linear arrows to correctly translate non-duplicable functions, e.g. higher-order arguments corresponding to components peripheral to the circuit.__ +__TL;DR What does it mean for a function to be used linearly? It means that function's _argument_ will be used linearly. Somewhat surprisingly, in a circuit context it means that the _output port_ of a higher-order argument is only driven by a single source. This means we need linear arrows to correctly translate non-duplicable functions, e.g. higher-order arguments corresponding to components peripheral to the circuit.__ I'm writing this post on the train on my way back from an amazing ZuriHac 2019, where I got to meet a lot of new people, many of them really excited about Clash! I also got to talk with some about the linear types feature that will hopefully hit GHC HEAD very soon. @@ -33,12 +33,12 @@ And then when a function is called, the circuits corresponding to the applied ar In many situations this is a straightforward process, but what happens when one of the arguments has a function type? {{< highlight haskell >}} -f :: (Int32 -> Int32) -> Int32 -> Bool -f h y = (h y) < 10 +f :: (Int16 -> Int32) -> Int16 -> Bool +f h y = (h y) < (10 :: Int32) -k :: Int32 -> Int32 +k :: Int16 -> Int32 -topEntity :: Int32 -> Bool +topEntity :: Int16 -> Bool topEntity x = f k x {{< / highlight >}} @@ -46,12 +46,12 @@ How many bits are needed for a port of type `(Int32 -> Int32)`? How would the in Clearly this idea of mapping arguments to input ports, and results to output ports, doesn't work when our arguments have a function type. So how does Clash handle this? Well, before converting the expressions to a circuit, uses a process called specialisation to transform the above code to: {{< highlight haskell >}} -fK :: Int32 -> Bool -fK y = (k y) < 10 +fK :: Int16 -> Bool +fK y = (k y) < (10 :: Int32) -k :: Int32 -> Int32 +k :: Int16 -> Int32 -topEntity :: Int32 -> Bool +topEntity :: Int16 -> Bool topEntity x = fK x {{< / highlight >}} @@ -70,19 +70,19 @@ Now the following concept is exactly described in the Geometry of Synthesis pape So in: {{< highlight haskell >}} -f :: (Int32 -> Int32) -> Int32 -> Bool -f h y = (h y) < 10 +f :: (Int16 -> Int32) -> Int16 -> Bool +f h y = (h y) < (10 :: Int32) -k :: Int32 -> Int32 +k :: Int16 -> Int32 -topEntity :: Int32 -> Bool +topEntity :: Int16 -> Bool topEntity x = f k x {{< / highlight >}} the component for `f` would get: * an additional `Int32` input port corresponding to the result of the `h` argument, -* and an additional `Int32` output port corresponding to the argument of `h`. +* and an additional `Int16` output port corresponding to the argument of `h`. Inside the component for `f` we would then: @@ -101,8 +101,8 @@ _TODO: create a picture making the above more intuiative._ Now let's say we change our definition of `f` to: {{< highlight haskell >}} -f :: (Int32 -> Int32) -> Int32 -> Int -> Bool -f h x y = (h x + h y) < 10 +f :: (Int16 -> Int32) -> Int16 -> Int16 -> Bool +f h x y = (h x + h y) < (10 :: Int32) {{< / highlight >}} i.e. apply the function `h` twice to different arguments. @@ -115,7 +115,7 @@ _TODO: create a picture making the above more intuiative._ There are two options here: 1. Duplicate the output (and input) ports of the `h` argument so that `x` and `y` can be connected to these outputs seperately; this behaviour basically corresponds to the specialisation transformation Clash applies already. -2. Use linear arrows +2. Use linear arrows, change the type signature to `f :: (Int16 -> Int32) -. Int16 -> Int16 -> Bool`, and have the type-checker disallow the duplicate use of `h`. # Synchronisation and the case for higher-order top-level functions You might argue that a first-order top-level function (`topEntity`) is a sensible restriction, after all, it's kind of the "entry point" into your entire circuit (much like `main :: IO ()` in regular Haskell program). From 98bd1b5a92bdd86276d32da856c4f277b5ed7194 Mon Sep 17 00:00:00 2001 From: Christiaan Baaij Date: Mon, 17 Jun 2019 16:56:44 +0200 Subject: [PATCH 17/17] Update 0006-linear-clash.md --- content/blog/0006-linear-clash.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/blog/0006-linear-clash.md b/content/blog/0006-linear-clash.md index 400b2d4..b2fb3fb 100644 --- a/content/blog/0006-linear-clash.md +++ b/content/blog/0006-linear-clash.md @@ -10,7 +10,7 @@ toc: false mathjax: false --- -__TL;DR What does it mean for a function to be used linearly? It means that function's _argument_ will be used linearly. Somewhat surprisingly, in a circuit context it means that the _output port_ of a higher-order argument is only driven by a single source. This means we need linear arrows to correctly translate non-duplicable functions, e.g. higher-order arguments corresponding to components peripheral to the circuit.__ +__TL;DR In the context of linear types, what does it mean for a function to be consumed exactly once? It means to apply it to a single argument, and consume its result only once. Somewhat surprisingly, in a circuit context it means that the output port of a higher-order argument is only driven by a single source. This means we need linear types to correctly translate non-duplicable functions, e.g. higher-order arguments corresponding to components peripheral to the circuit.__ I'm writing this post on the train on my way back from an amazing ZuriHac 2019, where I got to meet a lot of new people, many of them really excited about Clash! I also got to talk with some about the linear types feature that will hopefully hit GHC HEAD very soon.