Reputation:
Is it possible to use the Effect
constructor directly? e.g. foo = Effect "howdy!"
It seems like this should be possible. It appears to be a type constructor.
:kind Effect
Type -> Type
However, if I try to construct it an error gets thrown
Effect 1234
Unknown data constructor Effect
I can only create one 'indirectly' with pure
myeffect :: Effect Int
myeffect = pure 123
Am I missing something?
Upvotes: 1
Views: 332
Reputation: 80724
The signature Effect :: Type -> Type
means that if you take the word Effect
and attach a type to the right of it, the result of that will be another type. So:
Effect :: Type -> Type
Int :: Type
Effect Int :: Type
This does not say anything about creating values of type Effect
. That is:
Effect Int :: Type
x :: Effect Int
x = Effect 42 -- not necessarily allowed
For many types this happens to work just fine, for example:
Maybe Int :: Type
x :: Maybe Int
x = Just 42 -- perfectly valid
But it doesn't have to. It all depends on how the type is defined. For example:
data MyType a = Foo
MyType :: Type -> Type
MyType Int :: Type
x = Foo 42 -- not allowed
y = Foo -- allowed
Note that I use the word Foo
to construct values of MyType
, not the word MyType
. This is because they are different things. MyType
is the name of the type, and Foo
is the name of a constructor - which is a function that can construct (hence the name) values of a type. Other examples of constructors are Just
and Nothing
- both used to construct values of type Maybe
.
A constructor may have the same number of parameters as the type itself, or it can have fewer parameters, or more. For example:
data Type1 a = Ctor1 a
data Type2 a = Ctor2
data Type3 a = Ctor3 a a
x :: Type1 Int
x = Ctor1 42
y :: Type2 Int
y = Ctor2
z :: Type3 Int
z = Ctor3 42 84
So, to summarize: depending on how the type is defined, you may or may not use the name of the type to create values of that type, the way you're trying to do with Effect
.
(also, some types may have multiple constructors, e.g. data Maybe a = Just a | Nothing
, but this is already taking too long)
But all of this doesn't even apply to Effect
, because...
Effect
worksEffect
does not have any constructors at all. There is absolutely no way to directly create values of this type, regardless of parameters.
This is because Effect
is magic. A value of type Effect Int
is definitely NOT a sort of "box" that contains an Int
inside. No-no-no.
Instead, a value of type Effect Int
is a program, which, when executed, will eventually produce an Int
. You can't look inside it, you can't take it apart, the only thing you can do with it is execute it.
And how do you execute it? Easy! You return it from your main
function!
No, seriously, that's the only way to execute an Effect
. (well, ok, there's also unsafePerformEffect
, and then you can do it with FFI, but those are hacks for the initiated, don't go there)
The normal way you execute an effect is to return if from your main
function, and the runtime will take care of it. Boom!
Another way to look at it is that your whole program is one big (or small) Effect
. That's your program.
Another thing you can do with effect is to combine it with another effect using operator >>=
(or its evil twin =<<
). For example:
x = pure 40
y = x >>= \a -> a + 2
z = pure 42
Here, y
and z
are equivalent programs: both, when executed, will produce number 42
.
And this is the way you write programs in PureScript: you start with built-in ("magic") functions that produce effects, such as cwd
or readLine
or whatever, and then compose those effects with others via >>=
or =<<
or the do
notation (which is syntactic sugar for >>=
). Then, the resulting big effect, constructed out of many small ones, you return from your main
function - and voila, you got yourself a program!
Upvotes: 4