Reputation: 8195
I'm trying to wrap my head around Haskell's monads by actually trying to manually implement some of the used operators, like >>=
(bind). I just do this to try and get a better understanding of things, there is no practical use in this endeavor. But I get to a brick wall from the get go because code that appears like "code examples" in explanations of monads turn out not to be actually compilable code...
When I try to define my own bind
I get a type error. This code:
bind :: IO a -> (a -> IO b) -> IO b
(bind action1 action2) world0 =
let (a, world1) = action1 world0
(b, world2) = action2 a world1
in
(b, world2)
...gives me these (9 is the first line of the code above):
iom.hs:10:1:
Couldn't match expected type `t0 -> (t1, t2)'
with actual type `IO b'
The equation(s) for `bind' have three arguments,
but its type `IO a -> (a -> IO b) -> IO b' has only two
iom.hs:11:23:
Couldn't match expected type `t0 -> (t1, t2)'
with actual type `IO a'
The function `action1' is applied to one argument,
but its type `IO a' has none
In the expression: action1 world0
In a pattern binding: (a, world1) = action1 world0
iom.hs:12:23:
Couldn't match expected type `t2 -> (t0, t1)'
with actual type `IO b'
The function `action2' is applied to two arguments,
but its type `a -> IO b' has only one
In the expression: action2 a world1
In a pattern binding: (b, world2) = action2 a world1
I am just starting with an example from http://www.haskell.org/haskellwiki/IO_inside , just replacing >>=
with bind to prevent a name clash and defining it as a function not infox operator. This is the example provided as an explanation (copy pasted):
(>>=) :: IO a -> (a -> IO b) -> IO b
(action1 >>= action2) world0 =
let (a, world1) = action1 world0
(b, world2) = action2 a world1
in (b, world2)
Now if I replace the last line with return (b, world2)
I get this instead:
iom.hs:10:1:
Couldn't match expected type `t0 -> m0 (t1, t2)'
with actual type `IO b'
The equation(s) for `bind' have three arguments,
but its type `IO a -> (a -> IO b) -> IO b' has only two
iom.hs:11:23:
Couldn't match expected type `t0 -> (t1, t2)'
with actual type `IO a'
The function `action1' is applied to one argument,
but its type `IO a' has none
In the expression: action1 world0
In a pattern binding: (a, world1) = action1 world0
iom.hs:12:23:
Couldn't match expected type `t2 -> (t0, t1)'
with actual type `IO b'
The function `action2' is applied to two arguments,
but its type `a -> IO b' has only one
In the expression: action2 a world1
In a pattern binding: (b, world2) = action2 a world1
Upvotes: 1
Views: 285
Reputation: 34378
That happens because the IO inside tutorial uses a fictional (though inspired by the real thing) definition for IO
(see section 3 for details):
type IO a = RealWorld -> (a, RealWorld)
Using this definition, IO a
is actually a synonym for a function type, and so the extra argument your error messages refer to wouldn't be a problem. The actual IO
type is abstract, so you can't see or use in your code what it is actually made of.
If you want to run the article code yourself, use that definition while renaming IO
to e.g. MyIO
and change your other definitions accordingly.
Upvotes: 6
Reputation: 10783
As they say in the article, that definition of IO
is actually not correct. IO
is not a type synonym for a function type, it's a bit more mysterious than that. The code given only works if IO is a type synonym for a function because, if not, you are trying to specify three arguments for a function whose signature says it takes two arguments.
There is a Monad that works much more like what they are describing called State
.
Upvotes: 3