在过去的一周里,我一直在试图理解Haskell的“核心”类型和类型类(但总共只学习了不到两周的时间),我发现了一个问题:
- “Semigroupoid”是“Category”的概括,这意味着任何“Category”都可以通过忽略它自己的身份并定义
o = (.)
- 来轻松地成为“Semigroupoid”。
(<>) = mappend
import Prelude hiding (id, (.))
import Data.Semigroupoid
import Data.Semigroup
import Control.Category
import Data.Monoid
instance Semigroupoid c => Semigroup (c a a) where
(<>) = o
instance Category c => Monoid (c a a) where
mempty = id
mappend = (.)
main = putStrLn "Does not type-check!"
我不确定为什么这段代码没有编译成功,ghc编译器会显示以下错误信息:
All instance types must be of the form (T a1 ... an)
where a1 ... an are *distinct type variables*,
and each type variable appears at most once in the instance head.
但是事实是包含以下内容:
{-# LANGUAGE FlexibleInstances #-}
在文件的顶部可以修复所有问题。
上述表达的关系似乎没有在库中内置,而Semigroupoid和Category之间以及Semigroup和Monoid之间的关系是内置的。
这是否有特定原因,而我只是忽略了它?
也许这与神秘的“FlexibleInstances”有关?
任何见解都将不胜感激。
Nontrivial
不是一个类别。编译器无法知道这一点;实际上,任何人都可以通过定义孤儿instance Category Nontrivial
来使它成为一个类别。当然,真正的问题是,这不可能是“良好形式”的,因为s
和q
参数实际上是协变的,但是第一个参数必须是逆变的要求并没有在Category
类中以编译器能够理解的形式明确提到,那么它拒绝该实例的依据是什么? - leftaroundabout