为什么TypeSynonymInstances不允许在实例头中使用部分应用的类型同义词?

时间:2011-02-07 14:43:21

标签: haskell

我知道TypeSynomymInstances only allows fully applied type synonyms to be used in instance heads,但如果我可以使用使用了paritally应用的类型同义词,它似乎会很方便。

例如:

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

3 个答案:

答案 0 :(得分:30)

Haskell中根本不允许部分应用的类型同义词。部分应用的同义词实际上是一个函数,其输入是未应用的类型,其输出是类型。例如,这是布尔逻辑的编码:

type True x y = x
type False x y = y
type Not b x y = b y x
type And b1 b2 x y = b1 (b2 x y) y
type Or b1 b2 x y = b1 x (b2 x y)

要确定两个部分应用的类型同义词是否相等,类型检查器必须确定函数是否相等。这是一个难题,一般来说它是不可判定的。

答案 1 :(得分:9)

允许部分应用类型同义词的另一个问题是它们会使类型推断和实例选择基本上不可能。例如,假设在某些程序的上下文中,我想在thingy类型上使用Int -> String -> Int -> (Int, String)thingy的类型为forall a b e. a -> b -> e a b,因此我们可以将aInt统一,bString统一,但如果允许e要成为部分应用的同义词,我们可以

e = FuncSynonym (,)

e = FuncSynonym' Int (,) where type FuncSynonym' x f a b = x -> f a b

甚至

e = Const2 (Int -> (Int, String)) where Const2 a x y = a

类型推断的问题会比决定函数的相等性更糟糕;它需要考虑具有特定输入的指定输出的所有函数,或类似的更复杂的问题(想象一下只是尝试将a bInt统一起来。)

答案 2 :(得分:0)

我们知道Maybe的种类是*->*

因此它可能是Functor

的一个实例
   instance Functor Maybe where
       fmap :: f -> Maybe a -> Maybe b
       fmap f Nothing = Nothing
       fmap f (Maybe x)  = Maybe (f x)

第一个示例:

   {-# LANGUAGE TypeSynonymInstances #-}

   type MaybeAlias a = Maybe

   instance {-# OVERLAPPING #-} Functor (MaybeAlias Int) where
       fmap f functor = undefined

TypeSynonymInstances扩展名(几乎像字符串替换)的作用下,它等于

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

没关系,因为allow fully applied type synonyms to be used in instance heads


请参见另一个示例:

   {-# LANGUAGE TypeSynonymInstances #-}

   type MaybeAlias a b = Maybe

MaybeAlias Int是什么类型?是*->*->*

为什么?

如上面的@heatsink评论:

  

部分应用的同义词实际上是一个函数,其输入是未应用的类型,而输出是类型

立即解释:

根据type MaybeAlias a b = Maybe的定义:

MaybeAlias就像部分应用的功能:

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

MaybeAlias Int就像部分应用的功能:

(MaybeAlias Int) :: b -> Maybe

Maybe的种类为* -> *b的种类为*

所以MaybeAlias Int的种类是* -> (* -> *)

* -> (* -> *)等于* -> * -> *

以下代码无法正常工作的根本原因,因为Functor类型类仅接受类型为* -> *而不是* -> * ->*的类型!

   {-# LANGUAGE TypeSynonymInstances #-}

   type MaybeAlias a b = Maybe

   instance {-# OVERLAPPING #-} Functor (MaybeAlias Int) where
       fmap f functor = undefined

为什么下面的代码不起作用?

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接受类型为* -> * -> *

的类型

FuncSynonym就像部分应用的功能:

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

FuncSynonym e就像部分应用的功能:

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

a的种类为*

b的种类为*

a -> e a b的种类*

(FuncSynonym e)的种类为* -> * -> *

Example类型类接受类型为* -> * -> *的类型,但是为什么仍然不起作用?

这是ghc issue 785comment

中的另一个原因