以下文件Poly.hs
文件
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE RankNTypes #-}
module Poly () where
type ListModifier s = forall a. s -> [a] -> [a]
instance Monoid (ListModifier s) where
mempty = const id
mappend f g st = f st . g st
获取要投诉的类型检查器:
Poly.hs:8:10: Illegal polymorphic or qualified type: ListModifier s …
In the instance declaration for ‘Monoid (ListModifier s)’
Compilation failed.
最初我虽然不能组成排名2类型但是:
λ> :t (undefined :: forall a . a -> String ) . (undefined :: forall b . String -> b)
(undefined :: forall a . a -> String ) . (undefined :: forall b . String -> b)
:: String -> String
我认为Poly
模块在某种程度上具有固有的不一致性,但我无法解决问题。
答案 0 :(得分:7)
ListModifier
是类型别名,而不是“真实”类型。类型别名本质上是类型级别的宏,在实际类型检查之前总是由类型检查器扩展。这意味着您的实例声明等同于以下内容:
instance Monoid (forall a. s -> [a] -> [a]) where
即使允许 ,它也会与现有的Monoid (a -> b)
实例重叠,所以它仍然不起作用。然而,更大的问题是你不能在forall
- 量化类型上定义实例,因为从实例解析的角度来看它是没有意义的。
您可以做的是使用newtype
定义新类型而不是类型别名:
newtype ListModifier s = ListModifier (forall a. s -> [a] -> [a])
现在你可以定义一个Monoid
实例,因为类型类分辨率只需要查找ListModifier
类型,这个类型更容易匹配:
instance Monoid (ListModifier s) where
mempty = ListModifier (const id)
mappend (ListModifier f) (ListModifier g) = ListModifier (\st -> f st . g st)
或者,您可以保留类型别名并定义具有不同名称的新类型,例如ReifiedListModifier
,然后在其上定义实例,并且只能在需要存储{{1在容器中或使用类型类实例。