Search code examples
haskelltypesfunctorapplicative

Can Haskell Typeclasses be Partially Implemented?


I want to make a pair type to represent modular arithmetic. I made its constructor

{- LANGUAGE GADTs -}
data Zn e where
    Zn :: Integer -> Integer -> Zn Integer

because I would like to be able to fmap over it and all the things. So if I try to make it a Functor instance

instance Functor Zn where
    fmap f (Zn s n) = Zn s $ mod (f n) s

I get Could not deduce: b ~ Integer from the context: a ~ Integer. Of course it cannot deduce this because this data type does not have a meaningful notion of fmap :: (a -> b) -> Zn a -> Zn b for all a and b, but it does whenever a and b are such that one could actually construct Zn instances from them (ie Integer). I also tried having the Zn constructor and all methods require Integral e but I get a similar problem. In that case, s has type a so constructing a Zn with it and f n :: b fails. In the second case I could convert s from a to Integer and then to b but this is clunky. The whole thing is a bit clunky. I'm just doing it because I want to be able to implement Functor and Applicative to perform mod after mapping a function so I can just implement + as liftA2 (+) and so on. The modulus s should be part of the type but dependent types are not practical in Haskell as far as I know.

Is it possible to have a type with kind * -> * implement Functor only for some arguments?


Solution

  • You're looking for MonoFunctor. It's just like Functor, but works with a fixed inner type instead of being parametrically polymorphic. Here's how you'd implement it for your type:

    {-# LANGUAGE TypeFamilies #-}
    
    import Data.MonoTraversable
    
    data Zn = Zn Integer Integer
    
    type instance Element Zn = Integer
    
    instance MonoFunctor Zn where
        omap f (Zn s n) = Zn s $ mod (f n) s
    

    However, be warned that such an instance isn't exactly lawful. You may be better off just making a modMap function or something, to avoid people making bad assumptions about how it will work.