类型类中的非法多态或限定类型

fak*_*ake 0 polymorphism haskell

以下文件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
Run Code Online (Sandbox Code Playgroud)

获取要注意的类型检查器:

Poly.hs:8:10: Illegal polymorphic or qualified type: ListModifier s …
    In the instance declaration for ‘Monoid (ListModifier s)’
Compilation failed.
Run Code Online (Sandbox Code Playgroud)

最初我虽然它不能组成2级类型但是:

?> :t (undefined :: forall a . a -> String ) . (undefined :: forall b . String -> b)
(undefined :: forall a . a -> String ) . (undefined :: forall b . String -> b)
  :: String -> String
Run Code Online (Sandbox Code Playgroud)

我觉得这个Poly模块在某种程度上本质上是不一致的,但我不能指责问题.

Ale*_*ing 7

ListModifier是一种类型别名,而不是"真实"类型.类型别名本质上是类型级别的宏,在实际类型检查之前总是由类型检查器扩展.这意味着您的实例声明等效于以下内容:

instance Monoid (forall a. s -> [a] -> [a]) where
Run Code Online (Sandbox Code Playgroud)

即使是允许的,它会与现有的重叠Monoid (a -> b)情况,所以它仍然是行不通的.但是,更大的问题是您不能在forall-quantified类型上定义实例,因为从实例解析的角度来看它没有意义.

你可以做的是使用以下方法定义一个新类型而不是类型别名newtype:

newtype ListModifier s = ListModifier (forall a. s -> [a] -> [a])
Run Code Online (Sandbox Code Playgroud)

现在您可以定义一个Monoid实例,因为类型类分辨率只需要查找ListModifier类型,这在匹配时要简单得多:

instance Monoid (ListModifier s) where
  mempty = ListModifier (const id)
  mappend (ListModifier f) (ListModifier g) = ListModifier (\st -> f st . g st)
Run Code Online (Sandbox Code Playgroud)

或者,您可以保留类型别名并定义具有不同名称的新类型,例如ReifiedListModifier,然后在其上定义实例,并且只能在需要将ListModifier容器存储在容器中或使用类型类实例时执行换行.