可以输入以下T
在 Haskell 或其他函数式语言中正式定义?
类型T
包含函数,给定 X
中的对象集合(即一组) ,为该集合中的每个对象分配一个编号。
例如,假设我们有一个函数 t
来自T
。它的论点arg
必须是 X
中的对象集合(集) ,例如字符串列表 ['abc', 'def', 'xyz']。它的返回值必须是一个函数r
仅需要三个可能的参数: 'abc'
, 'def'
或'xyz'
,并返回一个数字。我特别不想r
在这种情况下只接受任何字符串作为参数。
一个例子可能是“排名函数”,它给定一个对象集合,以某种方式为每个对象分配一个排名。它不仅仅返回数字的集合;相反,它返回一个函数,该函数接受原始集合的任何成员,并返回该成员的排名。
当然,如果我稍微改变一下我的要求,事情就会变得非常简单。我可以问那个函数 t
只需获取对象集合并返回数字集合。这几乎是一样的,但又不完全相同。这样的定义需要一些额外的工作:我必须将输入集合中的对象与输出集合中的对象进行匹配。而且它也不会那么精确:返回的数字集合可能与输入对象不匹配(例如,可能有一个数字太多)。
如果我描述的约束不能表达为类型约束,并且应该以不同的方式强制执行,我不会感到惊讶。
编辑:我最初还要求定义一个类型 U
其中包含从 X
获取函数的函数转换为数字,并返回 T
类型的函数。但我没有很好地解释这一点,这只会让我的问题更加困惑。所以最好忽略我问题的这一部分。
最佳答案
T - 标记
好的,我想重命名您的类型以帮助理解它们。 T
将数字分配给值,并且由于我不确定容器的结构是什么(并且希望保持灵活性),因此我将弹出值和数字对 (x,n)
。我们称之为标记,因此重命名为 T
Tagger
,所以假设我知道你的集合类型是 Coll
X
的集合s 的类型为 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
.
我倾向于替换固定类型 X
和集合类型Coll
使用类型参数(如某些语言中的泛型,例如 Java)来提高代码重用:
data (Functor coll,Num n) => Tagger coll x n = Tgr (coll x -> coll (x,n))
所以现在我们坚持 coll
ection 类型是一个 Functor,所以我们可以使用 fmap
将函数逐点应用于集合(对于您的情况至关重要,任何集合类型都将是 Functor 的实例)。
我对 Tagger
的定义感到最满意为您T
,但您可以使用 CollTaggerXInt
如果你只有一种可能性 coll
, x
和n
.
U - 制作标签
您的U
type 用于将元素标记器转换为集合标记器。我想调用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
一起使用如f
, x
如a
和(x,n)
为b,并定义
liftT :: (Functor coll,Num n) => (x -> n) -> coll x -> coll (x,n)
liftT f = fmap tag where
tag x = (x,f x)
如果你想定义你的类型,好的,但我认为 liftT
可能是您的类型中唯一合理的函数 U
.
排名 - U+上下文
现在我认为你的排名示例很有用,所以让我们研究一下。排名函数需要检查集合的所有元素,因此我们将整个集合作为第一个参数,因此 rankfunction :: coll x -> x -> n
(在上下文 (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)
在使用 liftT 将其应用于每个元素之前,将其第一个参数(整个集合)传递给rank函数。这称为部分评估,对于此类事情非常方便。
关于haskell - 函数签名声明中集合可以是 "opened"吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12475690/