<div dir="ltr"><div>Hi Miao,</div><div><br></div><div>> ```<br></div><div>> interface Num {<br>> Num (+)(Num a, Num b);<br>> Num abs(Num a);<br>> Num fromInteger(Integer);</div><div>> ...<br></div><div>> }</div><div>> ```<br></div><div><br></div><div>I'm trying to follow through this and I'm afraid I'm not seeing how your example OOP interface would work.</div><div>What would the implementation of `AnyNum<Double>.abs` be? It seems like it has no way of knowing whether the argument actually contains a Double or not?<br></div><div><br></div><div>Wouldn't the `Num` interface instead need to be along the lines of the following?<br></div><div><br></div><div>```</div><div>interface Num<T> {</div><div> T (+)(T a, T b);</div><div> T abs(T a);</div><div> T fromInteger(Integer);</div><div>}</div><div>```</div><div><br></div><div>or possibly</div><div><br></div><div><div>```</div><div>interface Num<T> {</div><div> Num<T> (+)(Num<T> a, Num<T> b);</div><div> Num<T> abs(Num<T> a);</div><div> Num<T> fromInteger(Integer);</div><div>}</div><div>```</div></div><div><br></div><div>I'm thinking that the OOP version for your original Num interface would have the same unsafe casting issues that your haskell translation has.</div><div>Or could you add an example of how `AnyNum<Double>.abs` would be implemented in the OOP version?<br></div><div><br></div><div>--Aaron V.<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, May 26, 2022 at 3:18 AM Miao ZhiCheng via Haskell-Cafe <<a href="mailto:haskell-cafe@haskell.org">haskell-cafe@haskell.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">Hi Haskellers!<br><br>Here are some of my thoughts about polymorphism in Haskell especially the inclusion polymorphism, with questions in the<br>end.<br><br>~IGNORE THESE LHS BOILER PLATES~<br><br>> {-# LANGUAGE GADTs #-}<br>> module Main where<br>> import Unsafe.Coerce ( unsafeCoerce )<br><br>~IGNORE THESE LHS BOILER PLATES~<br><br>* Classification of Polymorphism<br><br>Let's assume that we are following the classification of polymorphism where there are four types of it:<br><br>?? Btw, does anyone have a good citation of this classification? I got it from all over the Internet instead:<br>e.g <a href="https://www.tutorialspoint.com/types-of-polymorphisms-ad-hoc-inclusion-parametric-and-coercion" target="_blank">https://www.tutorialspoint.com/types-of-polymorphisms-ad-hoc-inclusion-parametric-and-coercion</a><br><br>** Overloading Polymorphism<br><br>It allows function with same name to act in different manner for different types.<br><br>** Coercion Polymorphism<br><br>Also called as casting sometimes.<br><br>** Inclusion Polymorphism<br><br>Also called as subtyping. This allows to point derived classes using base class pointers and references.<br><br>** Parametric Polymorphism<br><br>Also called early Binding, it allows to use same piece of code for different types. We can get it by using templates.<br><br>** Sub Classifications<br><br>In terms of being ad-hoc or universal:<br><br>- Overloading and Coercion are ad-hoc,<br>- Inclusion and Parametric are universal.<br><br>In terms of being compile-time vs run-time:<br><br>- Coercion, Overloading, Parametric are all compile-time polymorphism,<br>- while only Inclusion is run-time polymorphism.<br><br>* Different Polymorphism in Haskell<br><br>In terms of their counter parties in Haskell language:<br><br>** Overloading Polymorphismin Haskell<br><br>I think type classes basically provides such overloading ad-hoc polymorphism.<br><br>Some thinks so too: <a href="https://stackoverflow.com/questions/6636107/how-does-haskell-handle-overloading-polymorphism" target="_blank">https://stackoverflow.com/questions/6636107/how-does-haskell-handle-overloading-polymorphism</a><br><br>> class Fooable a where<br>> foo :: a -> Int<br>> instance Fooable Int where<br>> foo = id<br>> instance Fooable Bool where<br>> foo _ = 42<br><br>** Coercion Polymorphism in Haskell<br><br>I think Haskell has both `Coercible` & `unsafeCoerce` for handling representational equality in compile time.<br><br>But I am not sure if c/c++ style of conercion between similar types such as int/float/double is something Haskell would<br>want to inject these magic conversion code ever.<br><br>** Parametric Polymorphism in Haskell<br><br>This is probably what Haskell is best at the most, demonstrated by the classic `map` function definition:<br><br>> map' :: (a -> b) -> [a] -> [b]<br>> map' _ [] = []<br>> map' f (x:xs) = f x : map' f xs<br><br>Note that, one could also combine parametric and overloading together using constraints:<br><br>> double :: Num a => a -> a<br>> double x = x + x<br><br>This `double` function is parametric, but constrained only to work with Num type classes, hence their implementations<br>are overloaded.<br><br>** Inclusion Polymorphism in Haskell<br><br>Ok, finally inclusion polymorphism is what I want to focus on and have some questions here.<br><br>Before that, I do want to mention one observation, inclusion polymorphism probably is most likely the old OOP habits<br>that die hard. For me at least, since I consider myself a recovering OOP run-time polymorphism addict, and my guess is<br>that unless the use case do need run-time polymorphism, e.g. run-time execution layer abstration, it is often better off<br>using other type of polymorphism to achieve the same result. And even Bjarne Stroustrup is flirting with the idea:<br>[[<a href="https://www.youtube.com/watch?v=xcpSLRpOMJM][Bjarne" target="_blank">https://www.youtube.com/watch?v=xcpSLRpOMJM][Bjarne</a> Stroustrup - Object Oriented Programming without Inheritance - ECOOP 2015]]<br><br>Let's think of translating this piece of pseudo OOP style code into haskell.<br><br>```<br>interface Num {<br> Num (+)(Num a, Num b);<br> Num (*)(Num a, Num b);<br> Num abs(Num a);<br> Num negate(Num a);<br> Num signum(Num a);<br> Num fromInteger(Integer);<br>}<br><br>interface Show {<br> String show(Show a);<br>}<br><br>class AnyNum<T> implements Num, Show {<br> // trivially implements Num Show interfaces<br>}<br><br>// Now we can use AnyNum<Int>, AnyNum<Double>, etc. through their Num or Show interfaces.<br>```<br><br>In Haskell though, thanks to the ability of having existential type, AnyNum is actually quite nice to write:<br><br>> data AnyNum where<br>> MkAnyNum :: (Num a, Show a) => a -> AnyNum<br><br>But in order to use AnyNum like using interfaces in our pseudo code, we would have to write these boiler plates and in<br>some cases using unsafeCoerce due to not using Typeable run-time information:<br><br>> instance Num AnyNum where<br>> (+) (MkAnyNum a) (MkAnyNum b) = MkAnyNum $ a + unsafeCoerce b<br>> (*) (MkAnyNum a) (MkAnyNum b) = MkAnyNum $ a + unsafeCoerce b<br>> abs (MkAnyNum a) = MkAnyNum . abs $ a<br>> negate (MkAnyNum a) = MkAnyNum . negate $ a<br>> signum (MkAnyNum a) = MkAnyNum . signum $ a<br>> fromInteger = MkAnyNum . fromInteger<br>> instance Show AnyNum where<br>> show (MkAnyNum a) = show a<br><br>Here is some test code that demonstrate how distressful unsafeCoerce is:<br><br>> main = do<br>> let a = MkAnyNum(1 :: Int)<br>> let b = MkAnyNum(2 :: Double)<br>> let c = MkAnyNum(3 :: Int)<br>> print $ show $ a + b<br>> print $ show $ a + c<br><br>Outputs are:<br>```<br>λ><br>"4611686018427387905"<br>"4"<br>```<br><br>Few observations:<br><br>- If there is at most one occurance of the usage of the type class, there is no need for the unsafeCoerce.<br>- Otherwise, unsafeCoerce is required, or otherwise those functions could be left to "undefined".<br><br>So my central questions for discussions are:<br><br>- Is inclusion polymorphism something we should use at all in Haskell?<br>- These boiler plate code maybe better be generated using Haskell template instead, is there one already, or should<br> there be one?<br><br><br>Cheers,<br>Miao</div>
_______________________________________________<br>
Haskell-Cafe mailing list<br>
To (un)subscribe, modify options or view archives go to:<br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
Only members subscribed via the mailman list are allowed to post.</blockquote></div>