<br><br>I&#39;m bashing together a simple command line geometry thing that let&#39;s you create shapes, move them around them, delete and edit them, test for intersections, etc. The motivation is to get a grip on Haskell IO and how it interacts with user defined datatypes.  I&#39;m using GHC.<br>
<br>The problem, which I&#39;ve tried to show as simply as possible in the abstracted code below, is that something seems to go horribly wrong with un-boxing (is this the correct terminology?) user defined type X&#39;s from IO(X)&#39;s. In the example below:<br>
<br>- enterCircle makes a Shape using the Circle cstr and boxes it in a return. And the type checker is happy with the function. <br><br>- But when the Shape is un-boxed in mainLoop then Haskell&#39;s type system (or GHC&#39;s?) has lost track of its Shapeness. Instead it sees it as a Pt2-&gt;Float. Which makes some sort of sense, but is useless (or at least needs ugly hacks to overcome) if you want to put your Circle in a List of Shapes.<br>
<br>- Even worse then the loss of Shapeness is that Haskell is letting me type enterCircle as returning an IO(Shape) - indeed that&#39;s what :t gives me in GCHI - but then disagrees with this type in mainLoop! This isn&#39;t what I was expecting from the vaunted Haskell type system; can someone explain this contradiction?<br>
<br>So. Does return fail to wrap up type info about user defined types in general? Is this correct Haskell behaviour? Or have I done something wrong?<br><br>If I haven&#39;t done something wrong, is there a standard idiom for overcoming this? I suppose I could use a show to convert the Circle to a string and then a read to convert it back in mainLoop&#39;s where, but this will mean uglier branching than I planned (the idea was to have a Map of fns that return shapes and just one branch in mainLoop to handle every kind of shape.) And it seems to make something of a nonsense of Haskell&#39;s type system as the entire Shape hierarchy will be reduced to IO(String) for these operations.<br>
<br><br><br><br><br><br>import Data.Map as Map<br>    <br>data Pt2 = Pt2 {x::Float, y::Float} deriving (Show, Read)<br><br>data Shape =   Circle   {origin::Pt2, radius::Float}<br>             | Square   {origin::Pt2, side  ::Float}<br>
             | Rect     {origin::Pt2, other ::Pt2} <br>               deriving (Show, Read)<br><br>enterCircle :: IO(Shape)<br>enterCircle = return (r) -- needs to rtn io (shape) because will take input here<br>       where r = Circle{origin=Pt2{x=1,y=2}, radius=4}<br>
             <br><br>mainLoop :: [Shape] -&gt; IO (String)            <br>mainLoop shapes = do<br>    putStrLn &quot;?&quot;<br>    cmd &lt;- getLine<br>    if cmd==&quot;q&quot;<br>      then<br>        return (&quot;done&quot;)<br>
      else do<br>        y &lt;- enterCircle <br>        mainLoop shapes&#39; <br>    where shapes&#39; = y : shapes<br>                    <br>main = mainLoop []<br><br><br><br>