Reputation: 1407
EDIT
All thee answers did explain it well enough, just one final thing, can anyone point me to the documentation about the types, so I can understand how the types are handled internally
I am trying to implement a wrapper type for IO, to understand types. I have created a IO' type which is actually using the IO to construct.
data IO' a = IO a
test :: String -> IO' String
test x = IO x
convert :: IO' String -> String
convert (IO x) = x
main = do
a <- getLine
return $ convert.test $ a
However now if I try to use IO to return an IO action then it fails, example the following function fails giving the expected vs actual type error:
fail :: IO String
fail = IO "test"
So in Haskell are types using same names get hidden? Also how do I understand whether I am using data constructor or type constructor when I call IO.
Finally, seems like a silly question but I tried to find the documentation for System.IO and later for List type as well, and am not able to find it.
Upvotes: 0
Views: 334
Reputation: 370357
You're defining two things: A type named IO'
and a constructor named IO
. Neither of them hide anything because the standard library defines neither a type named IO'
(only IO
) nor a constructor named IO
(the standard IO
type doesn't have any constructors). So since constructors and types live in different name spaces (meaning you can have a constructor and a type with the same name without any problems), nothing is being hidden.
So with your definitions, you now have the types IO
(referring to Prelude.IO
) and IO'
(referring to your type) and the constructor IO :: a -> IO' a
.
Your definition of fail
does not work because IO
constructs a value of type IO'
, not IO
. There is no connection between your IO
constructor and the IO
type, so there is no reason this should work.
Upvotes: 3
Reputation: 120731
Nothing is hidden in your code.
In Haskell, the type- and value-languages are strictly separated. Broadly speaking, everything to the right of a ::
or data
/newtype
/type
keyword (except the name-declaration for value constructors) lives in the type-level language, everything else lives in the value-level language.
┌─────┐ ┌──┐ ┌─┐
data │IO' a│ = │IO│ │a│
└─────┤ └value-level└┬┘
└─type-level─────┘
┌───────────┐
fail :: │ IO String │
└──────────type-level
┌────────────────┐
fail = IO "test" │
└───────────────value-level
The type-level IO
is unambiguously Prelude.IO
(because you named your type IO'
instead), whereas the value-level IO
is unambiguously the data constructor to IO'
that you defined yourself (because Prelude.IO
does not export any constructors called either IO
or otherwise).
Hiding would only become relevant if you actually used the same name IO
again for the type constructor:
import Prelude hiding (IO)
data IO a = IO a
test :: String -> IO String
test x = IO x
convert :: IO String -> String
convert (IO x) = x
fail' :: IO String
fail' = IO "test"
Upvotes: 4
Reputation: 2300
I am trying to implement a wrapper type for IO,
You did not though. There's no reference to the IO
type anywhere in your data declaration.
data IO' a = IO a
That IO
on the right-hand side is not the type IO
. It's not even a type. That is just the name you chose for the value constructor of your data type IO'
.
If you ask ghc the type of IO
you'll get,
> :t IO
IO :: a -> IO' a
You could have chosen any other name for it, e.g.
data IO' a = C a
It's just a constructor for values of type IO'
Upvotes: 4