Why doesn't TypeSynonymInstances allow partially applied type synonyms to be used in instance heads?

后端 未结 3 1838
离开以前
离开以前 2020-12-01 08:11

I know that TypeSynomymInstances only allows fully applied type synonyms to be used in instance heads, but it seems like it would be handy if I could use paritally applied t

3条回答
  •  生来不讨喜
    2020-12-01 08:37

    As we known Maybe's kind is *->*.

    So it could be a instance of Functor

       instance Functor Maybe where
           fmap :: f -> Maybe a -> Maybe b
           fmap f Nothing = Nothing
           fmap f (Maybe x)  = Maybe (f x)
    

    The first example:

       {-# LANGUAGE TypeSynonymInstances #-}
    
       type MaybeAlias a = Maybe
    
       instance {-# OVERLAPPING #-} Functor (MaybeAlias Int) where
           fmap f functor = undefined
    

    Under the effect of TypeSynonymInstances extension (almost like a String replace), it equals

          instance {-# OVERLAPPING #-} Functor Maybe where
           fmap f functor = undefined
    

    It is ok, because allow fully applied type synonyms to be used in instance heads


    See the other example:

       {-# LANGUAGE TypeSynonymInstances #-}
    
       type MaybeAlias a b = Maybe
    

    What's the kind of MaybeAlias Int now? It's kind is *->*->*.

    Why?

    As @heatsink comment above:

    A partially applied synonym is effectively a function whose inputs are the un-applied types and whose output is a type

    Explain it now:

    Under the defintion of type MaybeAlias a b = Maybe :

    MaybeAlias like a partially applied function:

    (MaybeAlias) :: a -> b -> Maybe
    

    MaybeAlias Int like a partially applied function:

    (MaybeAlias Int) :: b -> Maybe
    

    The Maybe 's kind is * -> *, b 's kind is *.

    So MaybeAlias Int 's kind is * -> (* -> *) .

    And * -> (* -> *) equals * -> * -> *.

    The root cause why the below code not working, because Functor typeclass only accept type that has kind * -> *, not * -> * ->*!

       {-# LANGUAGE TypeSynonymInstances #-}
    
       type MaybeAlias a b = Maybe
    
       instance {-# OVERLAPPING #-} Functor (MaybeAlias Int) where
           fmap f functor = undefined
    

    Why the below code not working?

    class Example e where
      thingy :: a -> b -> e a b
    
    -- legit, but awkward
    newtype FuncWrapper e a b = FuncWrapper { ap :: a -> e a b }
    instance (Example e) => Example (FuncWrapper e) where
      thingy _ = FuncWrapper . flip thingy
    funcWrapperUse :: (Example e) => e Int String
    funcWrapperUse = thingy 1 "two" `ap` 3 `ap` 4 `ap` 5
    
    -- not legal, but a little easier to use
    type FuncSynonym e a b = a -> e a b
    instance (Example e) => Example (FuncSynonym e) where
      thingy _ = flip thingy
    funcSynonymUse :: (Example e) => e Int String
    funcSynonymUse = thingy 1 "two" 3 4 5
    
    

    Example typeclass accept a type that has kind * -> * -> *

    FuncSynonym like a partially applied function:

       FuncSynonym :: e -> a -> b -> (a -> e a b)
    

    FuncSynonym e like a partially applied function:

       (FuncSynonym e):: a -> b -> ( a -> e a b)
    

    a 's kind is *,

    b 's kind is *,

    a -> e a b 's kind *

    (FuncSynonym e)'s kind is * -> * -> *

    Example typeclass accept a type that has kind * -> * -> *, but why still not work?

    It's the other reason in ghc issue 785 and comment

提交回复
热议问题