Boost logo

Boost :

Subject: Re: [boost] [Hana] Informal review request
From: Louis Dionne (ldionne.2_at_[hidden])
Date: 2015-03-07 15:00:17


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:
>
> [...]
>
> I see much more you datatype as a tag.

That's exactly what they are. However, Fusion and MPL did not see
tags for what they are actually: a powerful way of lifting the
type system one level higher up to make representation differences
unimportant. Fusion and MPL only saw tags as part of their dispatching
system. I think it's mostly a philosophical difference at this point.

> 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. For example, the Tuple data type c±‰”¥µÁ±•µ•¹Ñ•…Ì((€€€€´´Q¡”‘¥™™•É•¹Ð…ÑÕ…°É•ÁÉ•Í•¹Ñ…Ñ¥½¹Ì™½ÈÑÕÁ±•Ì(€€€‘…Ñ„QÕÁ±”À€ôQÕÁ±”À(€€€‘…Ñ„QÕÁ±”ā„€ôQÕÁ±”ā„(€€€‘…Ñ„QÕÁ±”ȁ„ˆ€ôQÕÁ±”ȁ„ˆ(€€€‘…Ñ„QÕÁ±”́„ˆŒ€ôQÕÁ±”́„ˆŒ(€€€€´´•ÑŒ¸¸¸((€€€€´´Q¡”QÕÁ±”•¹•É…±¥é•ÑåÁ”É•ÁÉ•Í•¹Ñ¥¹œ…±°Ñ¡½Í”ÕåÌ(€€€±…Í́QÕÁ±”ÐÝ¡•É”(€€€€€€€±•¸€èèÐ€´ø%¹Ð((€€€¥¹ÍÑ…¹”QÕÁ±”QÕÁ±”ÀÝ¡•É”(€€€€€€€±•¸|€ô€À((€€€¥¹ÍÑ…¹”QÕÁ±”€¡QÕÁ±”ā„¤Ý¡•É”(€€€€€€€±•¸|€ô€Ä((€€€¥¹ÍÑ…¹”QÕÁ±”€¡QÕÁ±”ȁ„ˆ¤Ý¡•É”(€€€€€€€±•¸|€ô€È((€€€¥¹ÍÑ…¹”QÕÁ±”€¡QÕÁ±”́„ˆŒ¤Ý¡•É”(€€€€€€€±•¸|€ô€Ì(€€€€´´•ÑŒ¸¸¸(()‘µ¥ÑÑ•‘±ä°Ñ¡”…‰½Ù”¥Ìµ¥ÍÍ¥¹œÍ½µ•Ñ¡¥¹œ™Õ¹‘…µ•¹Ñ…°¥˜Ý”Ý…¹ÐÑ¼)¥µÁ±•µ•¹Ð½Ñ¡•È™Õ¹Ñ¥½¹Ì±¥­”¡•…‘€°‰ÕЁѡ…Ёɕ…¡•ÌÑ¡”±¥µ¥Ð½˜)µä!…Í­•±°µ™Ô¸$Ñ¡¥¹¬±½½­¥¹œ…Ё!…Í­•±°ÌÑåÁ”™…µ¥±¥•ÌlÅtµ‡@§&÷f–FRÖ÷&R–ç6–v‡Bà £ââ²ââåУâà£ââF†—2—2&V6W6RF†—2çVæ6R—2÷föÇVçF&–Ç•òÆVgB6–FRâÖ÷&P£ââvVæW&ÆÇ’ÂF†RFW6–vâ6†ö–6R’ÖFRv2FòÆVfR&ÖWG&–0£ââFFG—W2FòF†RFö7VÖVçFF–öâÆWfVÂöæÇ’Â2—2Fö7VÖVçFV@£ââ–âF†R6V7F–öâ&÷WBvVæW&Æ—¦VBFFG—W5³Òà£à£â’6âVæFW'7FæBF†B–÷RvçBFòÆWBF†R6öç7G&–çB26öÖÖVçG2÷"XZÙH\ÙH\œ›ÜœÈ[Ü™H^XÚ] ‚‚‚ˆˆ\ÈH[™XYBˆˆØZYÛˆ\È\Ý\š[™ÈH\Ý[™›Ü›X[™]šY]ËÚ]HXZÙBˆˆ\ÈH˜Y[Ù™ˆ™]ÙY[ˆX][X]XØ[ÛÜœ™XÝ™\ÜÈ[™\ØXš[]BˆˆÙˆHXœ˜\žKˆÚ[H[˜H›ÝšY\ÈݝXÝ\™\È]Ø]\ÙžBˆˆH]ÜÈšYÛÜ›Ý\ÛKHØ[\Ù\œÈÈ™HX›HÈ\ÙHÜÙBˆˆÝXÝ\™\È[ˆH]ZXÚÈ[™\HØ^H\ÈHYX[ˆÙˆ™Z[™È[Ü™Bˆˆ›ÙXÝ]™HÚ[ˆ™YYY ˆ›Üˆ^[\KHÛÝ[›ÝØš™XݏˆˆÛÛY[Û™HÜš][™ÈÜÙ]YØÛÙWN‚ˆ‚ˆˆ]]È×ÜÝš[™ÈH×J]]È
HÈ ÊˆÛ۝™\ÈHÝŽœÝš[™È
‹ÈNˆˆ]]ÈÈH[˜NŽ›XZÙWÝ\J K ‹Œ‹˜X˜ÈŠNˆˆ]]È\ÈH[˜NŽ˜[œÙ›Ü›JË×ÜÝš[™ÊNˆ‚ˆˆÚ[˜ÙH X  ‹Œ˜[™˜X˜È˜È›ÝÚ\™HHÛÛ[[Ûˆ]H\H[™ˆˆHÚYÛ˜]\™HÙˆ˜[œÙ›Ü›X\È
݆ Functor F)
> >
> > transform : F(T) x (T -> U) -> F(U)
> >
> > , the above should normally be ill-formed. However, the library
> > makes such usage possible because I kept in mind that we're
> > working in a "dirty" heterogeneously-typed context. Bottom line:
>
> I don't think heterogeneous types are dirty. We need just a different
> type of function (Overloaded) to transform them.
>
> if you have an heterogeneous type as pair for example, the mathematical
> transform function should
>
> transform : pair(T,U) x (T -> R) x (U -> S) -> pair(R, S)
>
> As C++ has overloaded functions we don't need to pass two functions, but
> just an overloaded function.

That's an interesting point of view. However, with this approach,
you can't say that Pa¥Ì„Õ¹Ñ½È¸%Ё¥¹ÍÑ•…‰•½µ•Ì„€) ¥Õ¹Ñ½ÈlÉt¸ÕÉÑ¡•Éµ½É”°±•ÐÌÍ…äå½Ô¡…Ù”„Á…¥È¡P°P¤¸€)ÑÉ…¹Í™½É´¥ÌÑ¡•¸((€€€ÑÉ…¹Í™½É´€èÁ…¥È¡P°P¤à€¡P€´øH¤à€¡P€´øL¤€´øÁ…¥È¡H°L¤()ÑÉ…¹Í™½É´Í¡½Õ±¡•¹”ÍÑ¥±°É••¥Ù”Ñݼ™Õ¹Ñ¥½¹Ì°É•…É‘±•Í́½˜€)Ñ¡”™…ÐÑ¡…Ёݔ½Õ±Áɽ٥‘”„Í¥¹±”½Ù•É±½…‘•™Õ¹Ñ¥½¸¸()1•Ðµ”¹½ÜÕÍ”„ÑÕÁ±”¥¹ÍÑ•…½˜„Á…¥È…́…¸•á…µÁ±”‰•…ÕÍ”¥Ð€)ÍÑ¥­Ìµ½É”±½Í•±äÑ¼Ý¡…Ё¡…ÁÁ•¹Ì¥¸!…¹„€¡A…¥È¥Ì¹½Ð„Õ¹Ñ½È€)¥¸!…¹„¤¸ÑÉ…¹Í™½É´Ñ¡•¸‰•½µ•Ìè((€€€ÑÉ…¹Í™½É´€èQÕÁ±”¡PÄ°€¸¸¸°Q¸¤à€¡PÄ€´øHĤà€¸¸¸à€¡Q¸€´øI¸¤€(€€€€€€€€€€€€€€€€€€€€´øQÕÁ±”¡HÄ°€¸¸¸°I¸¤()¥ÉÍа¥˜å½ÔÕÍ”Ñ¡¥Ì…ÁÁɽ… °å½Ô…¸ÐÍ…äÑ¡…ЁQÕÁ±”¥Ì€)„Õ¹Ñ½È¸%Ё¡…́Ѽ‰”„8µÕ¹Ñ½È°Ý¡¥ ¥ÌÑ¡”8µ…ɝյ•¹Ð)•ÅÕ¥Ù…±•¹ÐÑ¼Ñ¡” ¥Õ¹Ñ½È¸ÕÉÑ¡•Éµ½É”°å½Ô¡…Ù”ò&÷f–FP¤âF–ffW&VçBgVæ7F–öç2Fò&R&ÆRFòG&ç6f÷&Ò—Bâ6òf÷"W†×ÆRÀ§v†VâG&ç6f÷&Ö–ærGWÆR†–çB–çB–çB’–÷Rv÷VÆB†fRFò6 ¢G&ç6f÷&Ò‡GWÆRƒÂ"Â2’À¢µÒ†–çB’’²&WGW&â’²²ÒÀ¢µÒ†–çB’’²&WGW&â’²²ÒÀ¢µÒ†–çB’’²&WGW&â’²²Т ¥F†Bw2æ÷B&†WFW&övVæV÷W2"&öw&ÖÖ–æs²—Bw2§W7BâWV—fÆVçBv’ö`§w&—F–ærÛܙ˘\ÈH[˜Ý[ÛˆÚÜÙHÛXZ[ˆ\ȝHÙ]Ùˆ[›Øš™XÝÈÚ]ÚXÚHØ[ˆÈ‹ˆYˆ\™H\™HØš™XÝÈ[ˆH\B]Û‰ÝÝ\ܝ–‹[ˆH›Ùܘ[H\È[ Y›Ü›YY ˆÛÛ˜Ù\Ú[]\È]XÚÛÜÙ\ˆÈ\Ë‚‚•Hš[˜Ú\H™Z[™[˜IÜÈÙ[™\˜[^™Y\\È\È™X[H]ÙH›YˆH\\ÈÙˆHØš™XÝÈ[™[ˆÛÛœÚY\ˆØš™XÝȝ\ ]ËYY™™\™[ \™\™\Ù[][ۜˈH[ÛÈ[šÈ]Ø[ˆ™HÙY[‚˜\ÈH][ÝY[ÙˆHÙ]Ùˆ[\\ÈžHH\]Z]˜[[˜ÙH™[][Û‚ˆ•ˆHYˆ[™Û›HYˆ[™H[Ù[^XÝHHØ[YHÛÛ˜Ù\Ȉ[ˆ^XÝHHØ[YHØ^B‚Ûۘܙ][KHX][X]XØ[[š]™\œÙHÙIÜ™HÛÜšÚ[™ÈÚ]\țݛۛHHÙ]È] ÜÈXÝX[HHÊÊÈØ]YÛÜžHÚ\™HØš™XÝÈ\™H\\˜[™[Üœ\Û\È\™H[˜Ý[. Hence, that "quotient" would have to
also take morphisms into account. But I'm reaching the end of my
math-fu now.

> [...]
>
> How the fact to have either<A,B> and maybe<A> makes it more dificult to
> interact with heterogeneous objects?

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 ”É”Ý½É­¥¹œÝ¥Ñ ¡•Ñ•É½•¹•½ṌÍÑÕ™˜¤è((€€€Ñ•µÁ±…Ñ”€ñÑåÁ•¹…µ”•™…ձаÑåÁ•¹…µ”°ÑåÁ•¹…µ”4ø(€€€½¹ÍÑ•áÁȁ…ÕѼµ…剔¡•™…ձЁ‘•˜°˜°4´¤ì(€€€€€€€É•ÑÕɸ´¹¥Í}¹½Ñ¡¥¹œ€ü‘•˜€è˜¡´¹Ù…°¹„¤ì(€€€ô()M••µÌ±•¥ÐüQ¡¥ÌÝ½É­Ìè((€€€µ…剔 Ä°mt¡¥¹Ð¤¤ìÉ•ÑÕɸ¤€¬€Äìô°}µ…剔ñ¥¹ÐùìÅô¤ì() ÕЁѡ¥Ì‘½•Ì¹½Ð°•Ù•¸Ñ¡½Õ ÍѐèéÑÕÁ±”ðø…¹ÍѐèéÑÕÁ±”ñ¥¹Ðø¡…Ù”)Ñ¡”Í…µ”•¹•É…±¥é•ÑåÁ”è((€€€µ…剔 (€€€€€€€ÍѐèéÑÕÁ±”ðùíô°(€€€€€€€mt¡¥¹Ð¤¤ìÉ•ÑÕɸÍѐèéµ…­•}ÑÕÁ±”¡¤¤ìô°(€€€€€€€}µ…剔ñ¥¹ÐùìÅô(€€€€¤ì()%Ё™…¥±ÌÝ¥Ñ (€€€€)•ÉɽÈ聥¹½µÁ…Ñ¥‰±”½Á•É…¹ÑåÁ•Ì€ ÑÕÁ±”𡹼…ɝյ•¹Ð¤øœ…¹€ÑÕÁ±”ñ¥¹Ðøœ¤(€€€É•ÑÕɸ´¹¥Í}¹½Ñ¡¥¹œ€ü‘•˜€è˜¡´¹Ù…°¹„¤ì(€€€€€€€€€€€€€€€€€€€€€€€xùùø€€ùùùùùùùùùø()´¹¥Í}¹½Ñ¡¥¹œ¥Ì¹½Ð„½¹ÍÑ…¹Ð•áÁÉ•ÍÍ¥½¸¥¹Í¥‘”Ñ¡”™Õ¹Ñ¥½¸¸€)%˜¥ÐÝ…Ì°Ý”½ÕW6R&ööÅóÆÒæ—5öæ÷F†–æsæFòW6R÷fW&ÆöF–æp§Fò–6²v†–6‚'&æ6‚vRw&RW†V7WF–ær–ç7FVBöbFö–ær—B@§'VçF–ÖRÂÆ–¶RvRFò&–v‡Bæ÷râF†—2—2W‡Æ–æVB–âF†R6V7F–öà¦öâF†RÆ–Ö—FF–öç2öb6öç7FW‡"³5Òà  £âà£ââ²ââåУâà£ââæ÷F–6RÖWF£§V÷FRà£â’vöæFW"–bF†RÖWF£§G&ç6f÷&Ò6÷VÆFâwBF¶R6&RöbV÷FRà ¤–b—BF¶W26&RöbV÷FRÂF†VâvRæVVBFòÇv—272FV×ÆFW0§Fò†–v†W"÷&FW"Æv÷&—F†×2â&6–6ÆÇ’ÂF†Bv÷VÆB&RÆ–¶R66WF–æp¦ÖWFgVæ7F–öç2–ç7FVBöbÖWFgVæ7F–öâ6Æ76W2–âF†RÕ–çFW&f6Rà¥F†W&R&RvööB&V6öç2æ÷BFòFòF†Bà  £â²ââåУà£â×’ö–çBv2Ö÷&Röâ†÷rF†RÆ–'&'’—26†V6¶–ærF†Rf—7B&wVÖVçBöb‚ˆˆ˜[œÙ›Ü›Hˆ[˜Ý܏ˆ
 OˆJH Oˆ[˜ÝÜŠJBˆˆYˆH[\[Y[][ÛˆXÛ\™\Ș[œÙ›Ü›H\ˆˆ]]Ș[œÙ›Ü›HH×H
]]È‹]]ȝ[ŠBˆˆÛÝ[‰ÝHHXœ˜\žHÚXÚÈ]H\™Ý[Y[È\ÜÙY[ˆˆ[™[ˆˆ™\ÜXÝH™\]Z\™[Y[Ï‚–Y\˝]]ÛÝ[™\]Z\™H[˜Ý][™È]]\ÈH[˜Ý[Ûˆ™œ›ÛH]H\HÈ]H\HKÚXÚ\È[\˜XÝXØ[ ˆ[ˆ\XÝ[\‚š]YX[œÈ]\΂ˆˆ˜[œÙ›Ü›JXZÙWÝ\J K ‹ ÊK×J[JHˆ™]\›ˆH
È NˆJN‚ÛÝ[›ÝÛܚˈ[œÝXYÛ™HÛÝ[™YYÈÜš]B‚ˆ˜[œÙ›Ü›JXZÙWÝ\J K ‹ ÊK[˜NŽ™[˜Ý[ۏ[
[
OŠ×J[JHˆ™]\›ˆH
È NˆJJN‚•[‹Ø^H[ÝH]™B‚ˆ˜[œÙ›Ü›JXZÙWÝ\J KÝŽœÝš[™ÞȘX˜ÈŸK^WØÛ\ÜÞßJKˆ[˜NŽ™[˜Ý[ۏÏÏÊÏÏÊOŠ×J]]È {
            ...
        }));

The way I see it, it's just not convenient. Doing it would
definitely force us to be mathematically correct though.
Instead, I aim to catch most programming errors by checking
that F is a Functor (which is easy). If you send in a random
function, then the compiler will tell you where you're wrong,
but Hana won't.

Regards,
Louis

[1]: http://goo.gl/fY8pcw
[2]: http://goo.gl/Iy4FKu
[3]: http://ldionne.github.io/hana/#tutorial-constexpr


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