haskell - 函数签名声明中集合可以是 "opened"吗?

标签 haskell types functional-programming language-comparisons

可以输入以下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 , xn .

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 , xa(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/

相关文章:

python - Suds:响应中未找到类型

java - 在存储在 XML 中的对象周围使用无类型包装器类,这不好吗?

angular - RXJS - 只发出比最后一个值更大的值

recursion - 尾递归删除列表中重复的连续条目

haskell - 如何在阅读时忽略多态可读类型?

Haskell 获取设置的线程名称

带有对象数组和接口(interface)的 typescript 交集类型

scala - 将列表拆分为列表列表

arrays - Haskell 位数组

haskell - 在 Haskell 脚本中完成的任何事情都可以在 GHCi session 中重现吗?