[Haskell-beginners] return (user defined type) confusion?

umptious umptious at gmail.com
Thu Apr 12 17:08:10 CEST 2012

I'm bashing together a simple command line geometry thing that let'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'm using GHC.

The problem, which I'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's from
IO(X)'s. In the example below:

- enterCircle makes a Shape using the Circle cstr and boxes it in a return.
And the type checker is happy with the function.

- But when the Shape is un-boxed in mainLoop then Haskell's type system (or
GHC's?) has lost track of its Shapeness. Instead it sees it as a
Pt2->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

- Even worse then the loss of Shapeness is that Haskell is letting me type
enterCircle as returning an IO(Shape) - indeed that's what :t gives me in
GCHI - but then disagrees with this type in mainLoop! This isn't what I was
expecting from the vaunted Haskell type system; can someone explain this

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?

If I haven'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'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's type
system as the entire Shape hierarchy will be reduced to IO(String) for
these operations.

import Data.Map as Map

data Pt2 = Pt2 {x::Float, y::Float} deriving (Show, Read)

data Shape =   Circle   {origin::Pt2, radius::Float}
             | Square   {origin::Pt2, side  ::Float}
             | Rect     {origin::Pt2, other ::Pt2}
               deriving (Show, Read)

enterCircle :: IO(Shape)
enterCircle = return (r) -- needs to rtn io (shape) because will take input
       where r = Circle{origin=Pt2{x=1,y=2}, radius=4}

mainLoop :: [Shape] -> IO (String)
mainLoop shapes = do
    putStrLn "?"
    cmd <- getLine
    if cmd=="q"
        return ("done")
      else do
        y <- enterCircle
        mainLoop shapes'
    where shapes' = y : shapes

main = mainLoop []
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/beginners/attachments/20120412/fa2e2c0f/attachment.htm>

More information about the Beginners mailing list