Reputation: 1459
Haskell newbie here. I was following this generative art tutorial over the net and came across the following code snippet. I ran it and it works just fine. The thing is I don't understand any bit of it.
type Generate a = RandT StdGen (ReaderT World Render) a
Is it a product type declaration ? if it is then is it possible to combine a group of types in parentheses like the above ? The way I see, it looks more like a function defined in a type or something like that.
Upvotes: 1
Views: 125
Reputation: 54979
Since no one has mentioned it so far, the term you’re looking for is monad transformer. Monad transformers let you add various effects on top of an existing type of actions. Examples include ReaderT
, StateT
, and MaybeT
. So in your example you have:
Render
is a Monad
that describes rendering actions.
ReaderT World
is a monad transformer; when applied to a monad, it produces a monad that can read an immutable environment of type World
. So ReaderT World Render
is a monad that describes Render
actions, and also stores a World
that can be read with ask
or asks
inside actions of this type, e.g., world <- ask
.
RandT StdGen
is a monad transformer which equips a monad with a random number generator of type StdGen
(a standard generator), which you can access using the methods of MonadRandom
: getRandom
, getRandoms
, getRandomR
, and getRandomRs
. So RandT StdGen (ReaderT World Render)
is a monad that can render things, read the state of the World
, and generate random numbers from a StdGen
, e.g., dieRoll <- getRandomR (1, 6)
.
The type
declaration just defines Generate
as an alias for RandT StdGen (ReaderT World Render)
, with one type parameter a
that indicates the result type of Generate
actions. Anywhere you see Generate Foo
, the compiler directly substitutes RandT StdGen (ReaderT World Render) Foo
.
Upvotes: 2
Reputation: 4360
I think it isn’t obvious how to parse this so let’s break it up
type
Generate a
=
RandT
StdGen
(ReaderT
World
Render)
a
So let’s break it down. Line 1 is type
this means “I’m here defining a type alias”. A type alias is a shorthand for another type and is exactly the same as the type it expands into. Note that data
means “I’m defining a new datatype and this is how to construct its values”.
Line 2 says “this type will be called Generate
and is a has parameter a
” that is the thing Generate
is a function from some type-level thing (in this case types e.g. Int
or Maybe Int
and not e.g. Maybe
)
Line 4 says that this type is equal to some application of the type constructor RandT
. This thing has kind * -> (* -> *) -> * -> *
and it’s meaning is roughly:
Let’s look at the second argument. This is an application of ReaderT
, a type-level thing of kind * -> (* -> *) -> * -> *
. The first argument is the thing you want to be able to read (the state of the world). The second is some Monad you want to be based on. In this case Render
which I assume let’s you build up the art as as you go. There is no third so just like currying in normal Haskell, the result of this has kind * -> *
, which is the kind that was wanted by RandT
.
The way to read this is: Generate
is a Monad that lets one use random number generation (with the standard generator), read a value of type World
, and render art.
Upvotes: 8