<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"><meta name=Generator content="Microsoft Word 15 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
.MsoChpDefault
        {mso-style-type:export-only;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:70.85pt 70.85pt 2.0cm 70.85pt;}
div.WordSection1
        {page:WordSection1;}
--></style></head><body lang=DE link=blue vlink="#954F72"><div class=WordSection1><p class=MsoNormal>Hi,</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>I don’t see any problem there. Why not just a pretty much do a one to one translation?</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>class Engine e where</p><p class=MsoNormal>  showEng :: e -> String</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>data Car e = Car</p><p class=MsoNormal>  { getId :: Int</p><p class=MsoNormal>  , getEng :: e</p><p class=MsoNormal>  }</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>instance Engine e => Show (Car e) where</p><p class=MsoNormal>  show this = "Car with " ++ (showEng $ getEng $ this)</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>data Steam = Steam { getCar :: Car Steam }</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>instance Engine Steam where</p><p class=MsoNormal>  showEng this = "id " ++ (show $ getId $ getCar $ this)</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>car :: Car Steam</p><p class=MsoNormal>car = Car 42 $ Steam car</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>And then just call „show car“. The should not be a problem with the looped reference.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Greetings</p><p class=MsoNormal>Jos</p><div style='mso-element:para-border-div;border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0cm 0cm 0cm'><p class=MsoNormal style='border:none;padding:0cm'><b>Von: </b><a href="mailto:dyaitskov@gmail.com">Daneel Yaitskov</a><br><b>Gesendet: </b>Freitag, 1. Mai 2020 01:33<br><b>An: </b><a href="mailto:haskell-cafe@haskell.org">haskell-cafe</a><br><b>Betreff: </b>[Haskell-cafe] [Haskell-Cafe] How to deal with looped referencesinside instances?</p></div><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>{-</p><p class=MsoNormal>Hi,</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>I am trying to translate a Java sample</p><p class=MsoNormal>with looped references below to Haskell.</p><p class=MsoNormal>I've found 2 solutions, but both of them look ugly,</p><p class=MsoNormal>because they require a helper class.</p><p class=MsoNormal>So I am looking for an advice for best practices on working</p><p class=MsoNormal>with looped references in polymorphic types.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>interface Engine {</p><p class=MsoNormal>   String showEng();</p><p class=MsoNormal>}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>class Car<E extends Engine> {</p><p class=MsoNormal>   int id;</p><p class=MsoNormal>   E eng;</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>   String show() {</p><p class=MsoNormal>     return "Car with " + eng.showEng();</p><p class=MsoNormal>   }</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>   int getId() { return id; }</p><p class=MsoNormal>}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>class Steam implements Engine {</p><p class=MsoNormal>   Car<Steam> car;</p><p class=MsoNormal>   Stream(Car<Steam> car) { this.car = car; }</p><p class=MsoNormal>   String showEng() {</p><p class=MsoNormal>     return "id " + car.getId();</p><p class=MsoNormal>   }</p><p class=MsoNormal>}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Car<Steam> car = new Car<>();</p><p class=MsoNormal>car.id = 42;</p><p class=MsoNormal>car.eng = new Stream(car);</p><p class=MsoNormal>car.show();</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>-}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>{-# LANGUAGE UndecidableInstances #-} -- Fix2 shortcoming</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>class Car c where</p><p class=MsoNormal>    getId :: c -> Int</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>class Engine e where</p><p class=MsoNormal>    showEng :: e -> String</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>data SteamEng c = SteamEng c</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>instance (Car c) => Engine (SteamEng c) where</p><p class=MsoNormal>    showEng (SteamEng c) = "id " ++ show (getId c)</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>{-</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>First solution is via ShowEng class.</p><p class=MsoNormal>I don't know how to tell type checker</p><p class=MsoNormal>that the type which is got after application of type function</p><p class=MsoNormal>is instantiating Engine class??</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>  instance (Engine eng) => Show (Car1 eng) where</p><p class=MsoNormal>      show (Car1 _ eng) = "Car1 with " ++ showEng eng</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>-}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>data Car1 eng = Car1 Int (eng (Car1 eng))</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>class ShowEng f where</p><p class=MsoNormal>    showEng2 :: (Car a) => f a -> String</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>instance ShowEng SteamEng where</p><p class=MsoNormal>    showEng2 = showEng</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>{-</p><p class=MsoNormal>A side note. Intuitive alternative for ShowEng which is not working!</p><p class=MsoNormal>showEng2 = showEng means showEng2 gets Engine, but</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>class HaveEngine f where</p><p class=MsoNormal>    cast :: (Car a) => f a -> f a</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>instance HaveEngine SteamEng where</p><p class=MsoNormal>    cast = id</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>...</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>instance (HaveEngine eng) => Show (Car1 eng) where</p><p class=MsoNormal>    show (Car1 _ eng) = "Car1 with " ++ (showEng (cast eng))</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>nor</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>instance (HaveEngine eng) => Show (Car1 eng) where</p><p class=MsoNormal>    show (Car1 _ eng) = "Car1 with " ++ (showEng eng)</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>-}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>instance Car (Car1 e) where</p><p class=MsoNormal>    getId (Car1 id _) = id</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>instance (ShowEng eng) => Show (Car1 eng) where</p><p class=MsoNormal>    show (Car1 _ eng) = "Car1 with " ++ (showEng2 eng)</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>c1 = Car1 42 (SteamEng c1)</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>{-</p><p class=MsoNormal>Second solution is removing argument from engine type parameter.</p><p class=MsoNormal>-}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>data Car0 eng = Car0 Int eng</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>instance Car (Car0 e) where</p><p class=MsoNormal>    getId (Car0 id _) = id</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>instance (Engine eng) => Show (Car0 eng) where</p><p class=MsoNormal>    show (Car0 _ eng) = "Car0 with " ++ showEng eng</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>{-</p><p class=MsoNormal>in this case I have to avoid infinite type and introducing</p><p class=MsoNormal>an extra wrapper and instantiating business logic classes for him.</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>  λ c0 = Car0 42 (SteamEng c0)</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>  <interactive>:30:6: error:</p><p class=MsoNormal>     • Occurs check: cannot construct the infinite type:</p><p class=MsoNormal>         car ~ Car0 (SteamEng car)</p><p class=MsoNormal>     • In the expression: Car0 (SteamEng c0)</p><p class=MsoNormal>       In an equation for ‘c0’: c0 = Car0 42 (SteamEng c0)</p><p class=MsoNormal>     • Relevant bindings include c0 :: car (bound at <interactive>:30:1)</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>-}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>newtype Fix2 f g = Fix2 (f (g (Fix2 f g)))</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>instance (Show (f (g (Fix2 f g)))) => Show (Fix2 f g) where</p><p class=MsoNormal>    show (Fix2 a) = show a</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>{-</p><p class=MsoNormal>  λ c0 = Car0 42 (SteamEng (Fix2 c0))</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>  <interactive>:62:1: error:</p><p class=MsoNormal>     • No instance for (Car (Fix2 Car0 SteamEng))</p><p class=MsoNormal>         arising from a use of ‘print’</p><p class=MsoNormal>     • In a stmt of an interactive GHCi command: print it</p><p class=MsoNormal>-}</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>instance (Car (f (g (Fix2 f g)))) => Car (Fix2 f g) where</p><p class=MsoNormal>    getId (Fix2 a) = getId a</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>c0 = Car0 42 (SteamEng (Fix2 c0))</p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>{-</p><p class=MsoNormal>Thanks,</p><p class=MsoNormal>Daniil</p><p class=MsoNormal>-}</p><p class=MsoNormal>_______________________________________________</p><p class=MsoNormal>Haskell-Cafe mailing list</p><p class=MsoNormal>To (un)subscribe, modify options or view archives go to:</p><p class=MsoNormal>http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</p><p class=MsoNormal>Only members subscribed via the mailman list are allowed to post.</p><p class=MsoNormal><o:p> </o:p></p></div></body></html>