My student assignment I'm doing for Haskell programming includes a task I'm a little bit puzzled to solve. The things are given so: an instance of Functor class to be created just for a set-based new type. There is a declaration of that:
newtype Set x = Set { contains :: (x -> Bool) }
It's a case for me to understand what means if fmap
serves to be applied to something like a set of predicates. When doing about previous tasks, I've already defined fmap
rather with functions like (+3)
(to alter integers), (toUpper)
(to strings) etc. It's first time I'm dealing with anything beyond normal types (various numerics, String, Char). There is my humble attempt to start:
instance Functor Set where
fmap f (Set x) = if (contains x) == True then Set (f x) else Set x
Surely, it's a nonsense code, but I suppose some True/False need to be evaluated before fmap
apllication goes well. But, first of all, would you please explain the matter of set of predicates to elaborate more sensible approach?
With this definition, it is actually impossible to define a Functor
instance for Set
. The reason for this is that your Set a
type contains a
in a negative position... that is, a
is an argument to a function, not a value. When that happens, the type constructor can be a contravariant functor (type class Contravariant
from the contravariant
package), but it cannot be a covariant functor (the Functor
type class).
Here's are definitions of those classes:
class Functor f where
fmap :: (a -> b) -> f a -> f b
class Contravariant f where
contramap :: (a -> b) -> f b -> f a
See the difference? In a contravariant functor, the direction of the function you pass in is flipped when it's lifted to operate on the functor type.
In the end, this should make sense. Your notion of a "set" is a test that tells you whether something qualifies or not. This is a perfectly good mathematical definition of a set, but it gives you different computational powers than the standard one. For example, you cannot get at the elements of your predicate-based sets; only wait to be given a potential element. If you have a Set Integer
, and a function f :: String -> Integer
, then you can test String
s by first converting them to Integer
s and testing those, so you can get from Set Integer
to Set String
. But having a g :: Integer -> String
doesn't let you test Strings
!
If this is an assignment, then either you've misunderstood the assignment, you've done some earlier step differently than expected (e.g., if you defined Set
yourself in an earlier part, maybe you need to change the definition), or perhaps your instructor is hoping you'll struggle with this and understand why Functor
cannot be defined.