T - 标记
好的,我想重命名您的类型以帮助理解它们。T
将数字分配给值,并且由于我不确定容器的结构是什么(并且希望保持灵活),因此我将在 pair 中弹出值和数字(x,n)
。让我们称之为标记,所以 rename T
Tagger
,所以假设我知道你的集合类型是sColl
的集合,所以我需要X
Coll X
type CollTaggerXInt = Coll X -> Coll (X,Int)
这使您想要的功能成为类型同义词。
但是,如果Int
太小而您想使用Integer
,或Double
其他数字类型怎么办?
data Num n => CollTaggerX n = CollTaggerX (Coll X -> Coll (X,n))
这意味着您可以X
使用任何固定类型的数值数据来标记值。(Num n =>
是断言 n 必须是数字类型的数据类型约束。)右侧的 CollTaggerX 通过将标记函数包装在轻量级构造函数中来确保类型安全。我们需要使用data
,而不是type
因为我已经参数化了n
.
我倾向于用类型参数(如某些语言中的泛型,例如 Java)替换固定类型X
和集合类型Coll
,以提高代码重用:
data (Functor coll,Num n) => Tagger coll x n = Tgr (coll x -> coll (x,n))
因此,现在我们坚持认为coll
ction 类型是 Functor,因此我们可以使用fmap
将函数逐点应用于集合(在您的情况下至关重要,任何集合类型都将是 Functor 的实例)。
我对Tagger
for your 的定义最满意T
,但CollTaggerXInt
如果您只有一种可能性,您可以使用coll
,x
和n
。
U - 制作标签
您的U
类型是将元素标记器转换为集合标记器。我想称之为Lift
ing,而不是U
. 如果您正在使用CollTaggerXInt
,则可以再次使用类型同义词:
type LiftXIntToTagger = (X -> Int) -> Coll X -> Coll (X,Int)
或者如果您使用更灵活的Tagger
定义,您可以编写
data (Functor coll,Num n) => Lifter coll x n = Lifter ((x -> n) -> coll x -> coll (x,n))
但这一切都让人觉得为此创建一个类型很疯狂,因为如果你有一个逐点函数,你可以使用它来提升它无论如何fmap
都适用于你的类型:coll
fmap :: Functor f => (a -> b) -> f a -> f b
所以我们可以将它与coll
as f
、x
asa
和(x,n)
as b 一起使用,并定义
liftT :: (Functor coll,Num n) => (x -> n) -> coll x -> coll (x,n)
liftT f = fmap tag where
tag x = (x,f x)
如果你想定义你的类型,好的,但我认为liftT
这可能是你的 type 中唯一合理的函数U
。
排名 - U+上下文
现在我认为您的排名示例很有用,因此让我们对此进行调查。rankfunction 需要检查集合的所有元素,所以让我们给它整个集合作为它的第一个参数,所以rankfunction :: coll x -> x -> n
(在 context 中(Functor coll,Num n)
)。
liftInContext :: (Functor coll,Num n) => (coll x -> x -> n) -> coll x -> coll (x,n)
liftInContext rankfunction mycoll = liftT (rankfunction mycoll) mycoll
在这里,该函数(rankfunction mycoll)
将其第一个参数——整个集合——传递给 rankfunction,然后使用 liftT 将其应用于每个元素。这称为部分评估,对于这类事情非常方便。