比方说,我们有以下几点:约束情况下
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilyDependencies #-}
type family CategoryLikeT p_a_b = t | t -> p_a_b
type IsCategoryLike p t a b = (t ~ CategoryLikeT (p, a, b))
class CategoryLike p where
(>>>) ::
(
IsCategoryLike p t1 a b,
IsCategoryLike p t2 b c,
IsCategoryLike p t3 a c
) => t1 -> t2 -> t3
然后,我们发现,这个编译罚款:
f ::
(
CategoryLike p,
IsCategoryLike p t1 a b,
IsCategoryLike p t2 b c,
IsCategoryLike p t3 c d,
IsCategoryLike p t4 a d
) => t1 -> t2 -> t3 -> t4
f x y z = x >>> y >>> z
但是,我们还没有定义任何实例呢。让我们做到这一点:
data BasicFunction
type instance CategoryLikeT (BasicFunction, a, b) = a -> b
instance CategoryLike BasicFunction where
(>>>) = flip (.)
而且“INTS”下,除了是一种类像,如果我们只是假设“A”和“B”都是Void
,例如: 数据BasicInt 类型实例CategoryLikeT( BasicInt,虚空,虚空)= INT
instance CategoryLike BasicFunction where
(>>>) = (+)
当然上述不起作用,因为在实例定义有关于“A”或“b”没有约束,所以没有机制保障>>>
得到都是一样的类型,因此(+)
不够一般。因此,我认为是做了以下内容:
首先,增加了约束类型:
type family CategoryConstraints p t a b
,然后加入到IsCategoryLike
像下面这样的定义:
type IsCategoryLike p t a b =
(t ~ CategoryLikeT (p, a, b), CategoryConstraints p t)
我们可以再加入以下约束:
type instance CategoryConstraints BasicInt t = (t ~ Int)
但是现在我们有一个问题。 f
不再起作用,给这个错误:
Could not deduce: CategoryConstraints p (CategoryLikeT (p, a, c)))
我们可以解决这个问题有两种方式:
首先,通过在f
加入IsCategoryLike p t5 a c
的制约。但是对于更复杂的函数,这可能会很快变得非常混乱,您必须为每个操作添加一个约束。同样微不足道的变化,如将(x >>> y) >>> z
更改为x >>> (y >>> z)
需要更改签名,当没有约束时不需要签名。
或者,可以完全省略类型签名,或者可以使用部分类型签名。
但是,我想保留完整类型的签名,但不增长并且难以维护。人们可以提出替代方法吗?
关键问题是,你可以用类型签名写'f'吗? – Clinton
@Clinton仍然不是一个很好的签名,但更好一点。至少它可以与可见类型的应用程序一起使用 – Alec