
Hilco, I am going to use a lot of Haskell concepts here, but I am a strong believer that using the correct terms empowers the learner to go out and continue their education on their own. *Your first question is is it possible to define Result as Result success failure and still create an instance of Functor?* The answer to that is *yes*. We can look up the definition of the *Functor typeclass* (use *:i Functor* in GHCI), and we can see the following: *class Functor (f :: * -> *) where*....
From that definition, we can see that we can have an instance of Functor for any type that has the *kind * -> **. It seems like you are familiar with treating type constructors as functions at the type level, so what we are saying here is that in order for a type constructor to be a functor, it *has* to be a type constructor that takes *one* type constant to yield another type constant. Your type *Result* has the kind ** -> * -> **. It takes two type constants, so we know that wont "fit" into Functor, and we have to partially apply the *Result* type constructor to get another type constructor with the kind ** -> **, which can have an instance of Functor.
What I think is missing from your understanding is this - if you change
your data declaration to be *Result success failure*, then your instance of
functor will only be able to modify the failure case. Why? Because when you
write your instance of functor, it will look like this: *instance Functor
(Result success) where...*. If we look at the signature of *fmap :: (a ->
b) -> f a -> f b*, and then we specialize so that *f ~ Result success*, we
get *fmap :: (a -> b) -> Result success a -> Result success b*. In other
words, you have already baked in the first type argument to *Result* when
you are writing your instance of Functor for it, and are not allowed to
change it anymore.
*Your second question I would like to be able to express that "result" is
not touched...*
I am assuming here that you are talking about this piece of code "fmap _
result@(Failure error) = result" using your original functor instance and
data Result failure success...
We can't express that result is not touched. Why? Because result *is* touched.
It has to be. As you yourself mentioned, on the left-hand side we have a
value of one type, and on the right-hand side we have a value of a
different type. Even though we don't witness the change at the value level,
we do have a change at the type level. So we can't express it because it is
not what is happening. Now, I get what you are saying - the result on the
left-hand side has the same data as the right-hand side, same data
constructor, etc, but it is still not the same value.
On your third question, regarding GHC being smart enough to realize a NOP,
I don't know.
I hope this helps!
On Sat, Mar 3, 2018 at 2:32 PM, Hilco Wijbenga
Hi all,
I'm trying to implement my own Result type (and yes, I'm aware you can abuse Either for this :-) ) but doing something as (seemingly?) simple as implementing a Functor instance was surprisingly difficult.
data Result failure success = Success success | Failure failure
instance Functor (Result failure) where fmap f (Success value) = Success (f value) fmap _ (Failure error) = Failure error -- fmap _ result@(Failure error) = result -- fmap _ result = result
1) Is it possible to define "Result" as "Result success failure" (instead of "Result failure success") and _still_ create an instance of Functor? 2) The two alternatives for fmap for the Failure scenario do not compile (the end result is "Result failure a" instead of "Result failure b") and that makes sense. But I would like to be able to express that "result" is not touched. Is there any way to do that? 3) And while wondering about that, is GHC smart enough to realize that "= Failure error" in the failure scenario is actually a NOP? (I'm just curious.)
Cheers, Hilco _______________________________________________ Beginners mailing list Beginners@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
-- Steven Leiva 305.528.6038 leiva.steven@gmail.com http://www.linkedin.com/in/stevenleiva