我知道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
答案 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
,因此我们可以将a
与Int
统一,b
与String
统一,但如果允许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 b
与Int
统一起来。)
答案 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
类型类接受类型为* -> * -> *
的类型,但是为什么仍然不起作用?