Boost logo

Boost :

Subject: Re: [boost] [Hana] Informal review request
From: Louis Dionne (ldionne.2_at_[hidden])
Date: 2015-03-08 12:59:55


Vicente J. Botet Escriba <vicente.botet <at> wanadoo.fr> writes:

>
> Le 07/03/15 21:00, Louis Dionne a écrit :
> > Vicente J. Botet Escriba <vicente.botet <at> wanadoo.fr> writes:
> >
> >> Le 07/03/15 17:38, Louis Dionne a écrit :
> >>> Vicente J. Botet Escriba <vicente.botet <at> wanadoo.fr> writes:
> >> [...]
> >>
> >> Do you have an equivalence in Haskell to your datatype/generalized type?
> > No, but shooting from the hip you could approximate them with type
> > classes.
>
> A type class that is instantiated with another type class?

Like I said, I don't know Haskell well enough to tell whether
there's a direct mapping between data types in Hana and something
else in Haskell. Is there an equivalent to Fusion/MPL tags in Haskell?

> [...]
>
> DoesЁµ•…¹ÌÑ¡…Ёå½Ô…É”…Íͽ¥…Ñ¥¹œ„€‰ÁÉ¥¹¥Á…°ˆÑåÁ”±…ÍÌ€(ø€¡½‰Ñ…¥¹•‰äÑ¡”™Õ¹Ñ¥½¸‘…Ñ…ÑåÁ”¤Ñ¼„‘…Ñ„ÑåÁ”°Ñ¡…Ё¥ÌÕÍ•Ñ¼€(ø¥¹ÍÑ…¹Ñ¥…Ñ”Ñ¡”½Ñ¡•ÈÑåÁ”±…ÍÍ•Ìü()$Ý…́©ÕÍЁÕÍ¥¹œÑ¡”QÕÁ±”ÑåÁ”±…Í́…́„¡…¬Ñ¼€‰É½ÕÀˆÑ¡”€)‘¥™™•É•¹ÐQÕÁ±•8É•ÁÉ•Í•¹Ñ…Ñ¥½¹ÌÕ¹‘•ÈÑ¡”Í…µ”Õµ‰É•±±„¸…¥¸°)$´¹½Ð„!…Í­•±°Ý¥é…ɐ…¹Ñ¡•É”µ¥¡Ð‰”„±•…¸Ý…äÑ¼‘¼¥Ð¸(((ø€øøl¸¸¹t(ø€øø¥˜å½Ô¡…Ù”…¸¡•Ñ•É½•¹•½ṌÑåÁ”…́Á…¥È™½È•á…µÁ±”°Ñ¡”µ…Ñ¡•µ…Ñ¥…°(ø€øøÑÉ…¹Í™½É´™Õ¹Ñ¥½¸Í¡½Õ±(ø€øø(ø€øø€€€€€€ÑÉ…¹Í™½É´€èÁ…¥È¡P±T¤à€¡P€´øH¤à€¡T€´øL¤€´øÁ…¥È¡H°L¤(ø€øø(ø€øø́ ¬¬¡…́½Ù•É±½…‘•™Õ¹Ñ¥½¹ÌÝ”‘½¸Ð¹••Ñ¼Á…Í́Ñݼ™Õ¹Ñ¥½¹Ì°‰ÕÐ(ø€øø©ÕÍЁ…¸½Ù•É±½…‘•™Õ¹Ñ¥½¸¸(ø€øQ¡…Н́…¸¥¹Ñ•É•ÍÑ¥¹œÁ½¥¹Ð½˜Ù¥•Ü¸!½Ý•Ù•È°Ý¥Ñ Ñ¡¥Ì…ÁÁɽ… °(ø€øå½Ô…¸ÐÍ…äÑB—"—2gVæ7F÷"â—B–ç7FVB&V6öÖW2£ââ&”gVæ7F÷"³%Òà£à£â&–v‡BâgVæ7F÷"†2öæÇ’öæRG—R&ÖWFW"â–â†6¶VÆ–÷R6âæ÷B‚ˆˆ˜[œÙ›Ü›HÚÝ[[˜ÙHÝ[™XÙZ]™HÛȝ[˜Ý[ۜ˙YØ\™\ÜÈÙ‚ˆˆH˜XÝ]ÙHÛÝ[›ÝšYHHÚ[™ÛHÝ™\›ØYY[˜Ý[Û‹‚ˆˆZ\Š 
HØ[ˆ™HÙY[ˆ\È[ˆ[œÝ[˜ÙHÙˆ[˜Ý܈\È\Ý

HÙ\Ë‚ˆˆÙH™YY[ˆ[X\ˆˆ[\]HÛ\ÜÈ‚ˆ\Ú[™ÈZ\•HZ\ ŽÂ‚”ÙYH™[ÝË‚‚‚ˆˆ]YH›ÝÈ\ÙHH\H[œÝXYÙˆHZ\ˆ\È[ˆ^[\H™XØ]\ÙH]ˆˆÝXÚÜÈ[Ü™HÛÜÙ[HÈÚ]\[œÈ[ˆ[˜H
Z\ˆ\È›ÝH[˜ÝÜ‚ˆˆ[ˆ[˜JK‚ˆ\O ‹‹ˆÚÝ[‰Ý™HH[˜Ý܈™Z]\‹‚ˆˆ˜[œÙ›Ü›H[ˆ™XÛÛY\΂ˆ‚ˆˆ˜[œÙ›Ü›Hˆ\J K ‹‹‹ŠH
 H OˆŒJH ‹‹ˆ
ˆ Oˆ›ŠBˆˆ Oˆ\JŒK ‹‹‹›ŠBˆ‚ˆˆš\œÝ Yˆ[ÝH\ÙH\È\›ØXÚ [ÝHØ[‰ÝØ^H]\H\ˆˆH[˜ÝÜ‹ˆ]\ÈÈ™HH‹Q[˜ÝÜ‹ÚXÚthe N-argument
> > equivalent to the BiFunctor. Furthermore, you have to provide
> > N different functions to be able to transform it. So for example,
> > when transforming a tuple(int, int, int), you would have to say
> >
> > transform(tuple(1, 2, 3),
> > [](int i) { return i + 1; },
> > [](int i) { return i + 1; },
> > [](int i) { return i + 1; }
> > )
>
> As pair<T,T>, and list<T> tuple<T,T,T> can be seen as an instance of a
> Functor. But not its heterogeneous variants.

Fine, but what about tuple<T, U, T>? Clearly, transform should
receive three different functions:

    transform : tuple<T, U, T> x (T -> A) x (U -> B) x (T -> C)
                                ->
                          tuple<A, B, C>

And•¹”Ý”ÍÑ¥±°¡…Ù”„€ÌµÕ¹Ñ½È€¡™½ÈÜ½”Ñ¡…Ёµ•…¹Ì¤¸€)$Ñ¡¥¹¬$´ÍÑ…ÉÑ¥¹œÑ¼Õ¹‘•ÉÍÑ…¹Ý¡•É”½Õȁ٥•Ý́‘¥Ù•É”è()e½Ô­••À½¸ÑÉ她œÑ¼Í•”¡•Ñ•É½•¹•½Ṍ‘…Ñ„ÍÑÉՍÑÕɕ́±¥­”€)ÑÕÁ±•Ì…́Áɽ‘ՍЁÑåÁ•Ì°Ý¡¥ Ñ¡•ä…É”…Ёѡ”µ½ÍЁ‰…Í¥Œ±•Ù•°¸()$±¥™ÐÑ¡”ÑåÁ”µÍåÍÑ•´½¹”±•Ù•°¡¥¡•ÈÕÀ…¹Í•”ÑÕÁ±•Ì…́„€)™¥á•µ±•¹Ñ …ÉÉ…ǻ½˜½‰©•Ñ́ݥѠÑ¡”Í…µ”€‰ÑåÁ”ˆ€¡•¹•É…±¥é•€)ÑåÁ”¤¸Q¡¥Ì…ÁÁɽ… ¡…́ͽµ”…‘Ù…¹Ñ…•Ì°±¥­”‰•¥¹œ…‰±”Ñ¼±½½¬)…Ё½‰©•Ñ́½˜Ñ¡”QåÁ”‘…Ñ„ÑåÁ”…́½‰©•Ñ́½˜Ñ¡”Í…µ”€‰ÑåÁ”ˆ¸)Q¡½Í”½‰©•Ñ́…±°¡…Ù”„½µµ½¸¥¹Ñ•É™…”°Ý¡¥ ½ÉÉ•ÍÁ½¹‘́Ѽ€)Ñ¡”€ñÑåÁ•}ÑÉ…¥ÑÌø¸(((ø€øQ¡…Н́¹½Ð€‰¡•Ñ•É½•¹•½ṎÁɽÉ…µµ¥¹œì¥ÐÌ©ÕÍЁ…¸•ÅÕ¥Ù…±•¹ÐÝ…䁽˜(ø€øÝɥѥ¹œ(ø€ø€€€€€€(ø€ø€€€€€ÈÄ€ô˜Ä¡ÐĤ(ø€ø€€€€€ÈÈ€ô˜È¡ÐȤ(ø€ø€€€€€€¸¸¸(ø€ø€€€€€É¸€ô™¸¡Ñ¸¤(ø€øâv†W&RF¶&RF†RVÆVÖVçG2öbGWÆRÂæBf¶&RF†P£ââgVæ7F–öç2ÖVBöâ—B'’F†RâÔgVæ7F÷"w2G&ç6f÷&Öà£ââv†BvR7GVÆÇ’vçB—0£âà£ââ#Òb‡C£ââ#"Òb‡C"£ââââà£ââ&âÒb‡F␣âà£ââv†W&Rf—2FVf–æVB0£âà£ââb¢†–çFW'6V7F–öâöbF†RFFG—W2öbF†RGWÆRw2VÆVÖVçG2£ââÓà£ââ‡6öÖR÷F†W"G—R£â’vÒ7W&RFö–ær7V6‚¶–æBöbG&ç6f÷&ÖF–öç2—2W6VgVÂâ†÷vWfW"F†R[˜ÝÜœÈX]\šX[^™H[\Ù[™\ˈ]\Èš[ˆ\ÜÙ[˜ÙH^XÝHHØ[YH[™È\ÈÚ]\[œÈÚ]H\Ú˜Ø]YÛÜžK^Ù\][ÝH™\XÙH\HˆžH™Ù[™\˜[^™Y\H‹‚‚‚ˆˆ[ˆÝ\ˆÛܙ˘\ÈH[˜Ý[ÛˆÚÜÙHÛXZ[ˆ\ȝHÙ]Ùˆ[ˆˆØš™XÝÈÚ]ÚXÚHØ[ˆÈ‹ˆYˆ\™H\™HØš™XÝÈ[ˆH\Bˆˆ]Û‰ÝÝ\ܝ–‹[ˆH›Ùܘ[H\È[ Y›Ü›YY ˆÛÛ˜Ù\ˆˆÚ[]\È]XÚÛÜÙ\ˆÈ\Ë‚‚ˆÈ[ÝHYX[ˆÊÊÌMËÌŒÛÛ˜Ù\ÏÈÛÝ[‰Ý\HÛ\ÜÙ\Ȉ[\™O‚–Y\ËÊÊÈÛÛ˜Ù\ˈH\ÝYX[]ÊÊÈÛÛ˜Ù\ÈÛÝ[[\Âœ]ÛۜݘZ[ÈÛˆ˜[Z[Y\ÈÙˆ\\ËÚ]Ý]]š[™ÈÈš^Z\‚œ™\™\Ù[][Û‹ˆ‚‚ˆˆË‹‹—Bˆ‚ˆˆÝÈH˜XÝÈ]™HZ]\Kˆ[™X^X™OOˆXZÙ\È][Ü™HYšXÝ[ˆˆ[\˜XÝÚ]]\›ÙÙ[™[Ý\ÈØš™X?
> > Let's try to implement a type _maybe<A>:
> >
> > template <typename A>
> > struct _maybe {
> > struct empty { };
> >
> > union { A a; empty e; } val;
> > bool is_nothing;
> >
> > constexpr _maybe() : val{empty{}}, is_nothing{true} { }
> > constexpr _maybe(A a) : val{a}, is_nothing{false} { }
> > };
> >
> > Now, let's try to implement, for example, the `maybe` function,
> > which has signature maybe :: B x (A -> B) x _maybe<A> -> B.
> > Remember that those A's and B's are actually generalized types,
> > not usual C++ types (we're working with heterogeneous stuff):
> >
> > template <typename Default, typename F, typename M>
> > constexpr auto maybe(Default def, F f, M m) {
> > €É•ÑÕɸ´¹¥Í}¹½Ñ¡¥¹œ€ü‘•˜€è˜¡´¹Ù…°¹„¤ì(ø€ø€€€€€ô(ø€ø(ø€øM••µÌ±•¥ÐüQ¡¥ÌÝ½É­Ìè(ø€ø(ø€ø€€€€€µ…剔 Ä°mt¡¥¹Ð¤¤ìÉ•ÑÕɸ¤€¬€Äìô°}µ…剔ñ¥¹ÐùìÅô¤ì(ø€ø(ø€ø ÕЁѡ¥Ì‘½•Ì¹½Ð°•Ù•¸Ñ¡½Õ ÍѐèéÑÕÁ±”ðø…¹ÍѐèéÑÕÁ±”ñ¥¹Ðø¡…Ù”(ø€øÑ¡”Í…µ”•¹•É…±¥é•ÑåÁ”è(ø€ø(ø€ø€€€€€µ…剔 (ø€ø€€€€€€€€€ÍѐèéÑÕÁ±”ðùíô°(ø€ø€€€€€€€€€mt¡¥¹Ð¤¤ìÉ•ÑÕɸÍѐèéµ…­•}ÑÕÁ±”¡¤¤ìô°(ø€ø€€€€€€€€€}µ…剔ñ¥¹ÐùìÅô(ø€ø€€€€€€¤ì(ø€ø(ø€ø%Ё™…¥±ÌÝ¥Ñ (ø€ø€€€€€€(ø€ø•ÉɽÈ聥¹½µÁ…Ñ¥‰±”½Á•É…¹ÑåÁ•Ì€ ÑÕÁ±”𡹼…ɝյ•¹Ð¤øœ…¹€ÑÕÁ±”ñ¥¹Ðøœ¤(ø€ø€€€€€É•ÑÕɸ´¹¥Í}¹½Ñ¡¥¹œ€ü‘•˜€è˜¡´¹Ù…°¹„¤ì(ø€ø€€€€€€€€€€€€€€€€€€€€€€€€€xùùø€€ùùùùùùùùùø(ø(øQ¡¥ÌÍ••µÌ¹½Éµ…°Ñ¼µ”¸()%Ё}¥Í|¹½Éµ…°°‰ÕЁ¥ÐÌ¹½ÐÕÍ•™Õ°¥¸„½¹Ñ•áЁ½˜‘•…±¥¹œÝ¥Ñ €)¡•Ñ•É½•¹•½Ṍم±Õ•Ì°‰•…ÕÍ”å½Ô…¸ÐÉ•ÑÕɸ½‰©•ÑÌbF–ffW&Vç@§G—W2g&öÒF†BgVæ7F–öââv†BvRæVVB—2Fò7F÷&RF†R–æf÷&ÖF–öà§&WV—&VBFòÖ¶RF†B'&æ6‚–âF†RÖ–&Rw2G—RÂæBF†VâvR6âÝ[^™\ÜÚ[Ûˆ[œÚYHH[˜Ý[Û‹‚ˆˆYˆ]Ø\ËÙHÛÝ[\ÙH›ÛÛÏKš\×Û›Ý[™Ï˜È\ÙHÝ™\›ØY[™ÂˆˆÈXÚÈÚXÚœ˜[˜ÚÙIÜ™H^XÝ][™È[œÝXYÙˆÚ[™È]]ˆˆ[[YKZÙHÙHÈšYÚ›Ýˈ\È\È^Z[™Y[ˆHÙXÝ[Û‚ˆˆÛˆH[Z]][ÛœÈÙˆÛÛœÝ^ˆÌ×K‚‚ˆÙ\È]YX[œÈ][Ý\ˆ]H\\ÈX^X™H[™Z]\ˆ\™H\ØX›HÛ›H\ȏˆY]K\›Ùܘ[[Z[™ÈÛÛÏÈHÛ‰ÝÙYHÚ\™HÛÝ[H\ÙH[H][‹][YK‚‚–[ÝIÜ™HšYÚ ^H\™H[ÜÝH\Ù[\ÜÈ][[YK\ÝZÙH˜›ÛÜÝŽ›Ü[Û˜[[™›ÛÜÝŽ˜\šX[\™HÛÛ\][H\Ù[\ÜÈ]˜ÛÛ\[K][YKˆ] ÜÈ^XÝHHÚ[È[˜H\ÈHÛY]\›Ùܘ[[Z[™×È›Xœ˜\žK‚‚”][Ý[™Èœ›ÛHX^X™IÜÈØÝ[Y[][ۈ̗N‚ˆˆË‹‹—BˆÝÙ]™\‹\™H\È[ˆ[\ܝ[\Ý[˜Ý[ÛˆÈXZÙH™]ÙY[ˆˆX^X™H[™::optional: just(x) and nothing do not share
    the same type. Hence, whether a just or a nothing will be
    returned from a function has to be known at compile-time for
    the return type to be computable at compile-time. This makes
    Maybe well suited for static metaprogramming tasks but very
    poor for anything dynamic.

> >
> >> [...]
> >>
> >> My point was more on how the library is checking the fist argument of
> >> Transform is a Functor and that the second argument is a "function" from
> >> the Functor's underlying type T to another type U.
> >>
> >> transform : Functor<T> x (T -> U) -> Functor(U)
> >>
> >> If the implementation declares transform as
> >>
> >> auto transform = [] (auto F, auto Fun)
> >>
> >> Couldn't the the library c¬Ñ¡…Ёѡ”…ɝյ•¹Ñ́Á…ÍÍ•¥¸…¹Õ¸(ø€øøÉ•ÍÁ•ÐÑ¡”É•Åեɕµ•¹ÑÌü(ø€øe•Ì°‰ÕЁѡ…ЁݽձÉ•ÅեɔÕ¹€ÍÑ…Ñ¥¹œÑ¡…Ё¥Ð¥Ì„™Õ¹Ñ¥½¸(ø€ø™É½´‘…Ñ„ÑåÁ”PÑ¼‘…Ñ„ÑåÁ”T°Ý¡¥ ¥Ì¥µÁÉ…Ñ¥…°¸%¸Á…ÉÑ¥Õ±…È(ø€ø¥Ðµ•…¹ÌÑ¡…Ёѡ¥Ìè(ø€ø€€€€€€(ø€ø€€€€€ÑÉ…¹Í™½É´¡µ…­•}ÑÕÁ±” Ä°€È°€Ì¤°mt¡¥¹Ð¤¤ì(ø€ø€€€€€€€€€É•ÑÕɸ¤€¬€Äì(ø€ø€€€€€ô¤ì(ø€ø(ø€øÝ½Õ±¹½ÐÝ½É¬¸%¹ÍÑ•…½¹”Ý½Õ±¹••Ñ¼Ýɥє(ø€ø(ø€ø€€€€€ÑÉ…¹Í™½É´¡µ…­•}ÑÕÁ±” Ä°€È°€Ì¤°¡…¹„èé™Õ¹Ñ¥½¸ñ¥¹Ð¡¥¹Ð¤ø¡mt¡¥¹Ð¤¤ì(ø€ø€€€€€€€€€É•ÑÕɸ¤€¬€Äì(ø€ø€€€€€ô¤¤ì(ø€ø(ø€øQ¡•¸°Í…äå½Ô¡…Ù”(ø€ø(ø€ø€€€€€ÑÉ…¹Í™½É´¡µ…­•}ÑÕÁ±” Ä°ÍѐèéÍÑÉ¥¹ì‰…‰Œ‰ô°µå}±…ÍÍíô¤°(ø€ø€€€€€€€€€¡…¹„èé™Õ¹Ñ¥½¸ðüüü üüü¤ø¡mt¡…ÕѼà¤ì(ø€ø€€€€€€€€€€€€€€¸¸¸(ø€ø€€€€€€€€€ô¤¤ì(ø€ø(ø€øQ¡”Ý…ä$Í•”¥Ð°¥ÐÌ©ÕÍЁ¹½Ð½¹Ù•¹¥•¹Ð¸½¥¹œ¥Ð÷VÆ@£ââFVf–æ—FVÇ’f÷&6RW2Fò&RÖF†VÖF–6ÆÇ’6÷'&V7BF†÷Vv‚à£ââ–ç7FVBÂ’–ÒFò6F6‚Ö÷7B&öw&ÖÖ–ærW'&÷'2'’6†V6¶–æp£ââF†Bb—2gVæ7F÷"‡v†–6‚—2V7’’â–b–÷R6VæB–â&æFöУââgVæ7F–öâÂF†VâF†R6ö×–ÆW"v–ÆÂFVÆ–÷Rv†W&R–÷Rw&Rw&öærÀ£ââ'WB†ævöâwBà£âB˜HÙ]ÙˆÛÛ[[ÛˆÛÛ˜Ù\ËÚXÚHžHÈ[X›ÙH[ˆHÛÛ˜Ù\Ù‚™]H\Kˆ\™IÜÈHÛX[Ù[™\˜[^˜][ÛˆZ\ÜÚ[™Èœ›ÛH^H[™\œÝ[™[™ÂÈœšYÙHHØ\™]ÙY[ˆÛÛ˜Ù\È[™]H\\ËÚXÚH[šÈ\™BHØ[YH[ˆH[™ ˆÙYHH™[X\šÈ]H[™ÙˆHÙXÝ[ÛˆÛ‚™Ù[™\˜[^™Y]H\\ÈÌ×K‚‚‚ˆH[šÈ]H™YYÈ[™\œÝ[™™]\ˆHØÛÜHÙˆHXœ˜\žK\ȏˆ[˜HH\™H[˜Ý[Û˜[›Ùܘ[[Z[™ÈXœ˜\žH܈[›Ý\ˆØ^HÈÈ\™HˆY]K\›Ùܘ[[Z[™È܈›Ý]HØ[YH[YK]™\ÝšXÝYÈHˆ[Z]][ÛœÈÙˆH[\œÙXÝ[ۏ‚“ZÙH\Ú[Û‹[˜H\ÈHXœ˜\žH]œšYÙ\È™]ÙY[ˆ[[YH[™˜ÛÛ\[K][YKˆ˜\ÚXØ[K[ÝHØ[ˆX[š\[]HÙ\]Y[˜Ù\ÈÚ]š]\›ÙÙ[™[Ý\ÈØš™XÝÈ[ˆ[K]Z\ˆ[™Ý\ÈÈ™HÛ›ÝÛ‚˜]ÛÛ\[K][YKˆHÛ›ÝÈre's a way to generalize this so that
it works with homogeneous sequences whose size is known at runtime
too, but I'm not tackling this right now.

Then, type-level computations come for free when you have
heterogeneous sequences, but we had just never saw it as
clearly as we do now.

Hana is not just a "pure functional" library that works at runtime.
It's a generalized Boost.Fusion which happens to use concepts from
the functional paradigm because it's convenient.

Regards,
Louis

[1]: https://github.com/ldionne/hana-thesis
[2]: http://ldionne.github.io/hana/structboost_1_1hana_1_1_maybe.html
[3]: http://ldionne.github.io/hana/index.html#tutorial-hetero


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk