Haskell 收藏可以是“收藏”吗;开放式;内部函数签名声明?
以下类型Haskell 收藏可以是“收藏”吗;开放式;内部函数签名声明?,haskell,types,functional-programming,language-comparisons,Haskell,Types,Functional Programming,Language Comparisons,以下类型T是否可以用Haskell或其他函数式语言正式定义 类型T包含函数,给定X中对象的集合(即一组),为该集合中的每个对象分配一个编号 例如,假设我们有一个来自t的函数t。它的参数arg必须是X中对象的集合(集合),例如字符串列表['abc','def','xyz']。其返回值必须是只接受三个可能参数的函数r,'abc','def'或'xyz',并返回一个数字。在这种情况下,我特别不希望r只接受任何字符串作为参数 例如,“秩函数”,它给定一组对象,以某种方式为每个对象分配一个秩。它不仅仅返回
T
是否可以用Haskell或其他函数式语言正式定义
类型T
包含函数,给定X
中对象的集合(即一组),为该集合中的每个对象分配一个编号
例如,假设我们有一个来自t
的函数t
。它的参数arg
必须是X
中对象的集合(集合),例如字符串列表['abc','def','xyz']。其返回值必须是只接受三个可能参数的函数r
,'abc'
,'def'
或'xyz'
,并返回一个数字。在这种情况下,我特别不希望r
只接受任何字符串作为参数
例如,“秩函数”,它给定一组对象,以某种方式为每个对象分配一个秩。它不仅仅返回一组数字;相反,它返回一个函数,该函数接受原始集合的任何成员,并返回该成员的秩
当然,如果我稍微改变一下我的要求,事情就会变得非常简单。我可以要求函数t
只获取一组对象并返回一组数字。这差不多,但不完全相同。这样的定义需要一些额外的工作:我必须将输入集合中的对象与输出集合中的对象进行匹配。而且它也不会那么精确:返回的数字集合可能与输入对象不匹配(例如,可能有一个数字太多)
如果我描述的约束不能表示为类型约束,并且应该以不同的方式强制执行,我不会感到惊讶
编辑:我最初还要求定义一个类型U
,其中包含将函数从X
转换为数字的函数,并返回类型T
的函数。但我没有很好地解释这一点,这只会让我的问题更加混乱。所以最好忽略我问题的这一部分。编辑:根据问题的更新,我已经完全重写了这个答案
暂时忽略对类型的强调,采取实际的方法,让我们在Haskell中构建这个功能。首先,这里有一个函数,给定一个函数、一个对象列表和一个对象,如果该对象在列表中,则将该函数应用于该对象
u f list x = assert (x `elem` list) $ f x
(assert函数来自控件。异常
)这也可以通过保护实现:
u f list x | (x `elem` list) = f x --similar but gives a slightly different error msg
在ghci中运行一些示例可提供以下内容:
*Main> u (+1) [1,2,3] 1
2
*Main> u (+1) [1,2,3] 2
3
*Main> u (+1) [1,2,3] 3
4
*Main> u (+1) [1,2,3] 4
*** Exception: test.hs:3:14-19: Assertion failed
但是,这不是非常安全的代码,因为没有静态保证函数不会以这种方式调用而导致崩溃
另一种方法是使用Maybe
类型
u' f list x = if elem x list then Just (f x) else Nothing
具有以下行为:
*Main> u' (+1) [1,2,3] 2
Just 3
*Main> u' (+1) [1,2,3] 3
Just 4
*Main> u' (+1) [1,2,3] 4
Nothing
这仍然不能静态地保证函数不会以错误的方式调用,但它可以静态地保证任何基于返回值的结果必须同时处理Just result
和Nothing
。这还有一个优点,那就是可能是一个单子,这可以被认为是可能失败的计算。这样你就可以像这样轻松地连接电话了
*Main> let func = u' (+1) [1,2,3]
*Main> func 1
Just 2
*Main> func 1 >>= func
Just 3
*Main> func 1 >>= func >>= func
Just 4
*Main> func 1 >>= func >>= func >>= func
Nothing
在哈斯克尔,这似乎是解决此类问题的最佳实用方法。然而,问题是,是否有一种类型专门固定了这样一个函数。让我们看看这些函数的类型:
u :: Eq x => (x -> a) -> [x] -> x -> a
u' :: Eq x => (x -> a) -> [x] -> x -> Maybe a
这两种类型都不要求列表中的成员资格决定它们是否有效。我想把它作为一种类型来工作的唯一方法是将集合本身看作一种类型。调用该类型col
,然后我们就可以
u :: (col -> x) -> col -> x
但这不仅没有什么实用价值,也没有精确地定义这些函数。基于成对的方法也不适用。根据我的经验,试图构造限制性很强的类型,比如只包含['abc','def','xyz']
中的值的类型,是不太实际的。T-Tagging
好的,我想重命名您的类型以帮助理解它们T
将数字分配给值,由于我不确定容器的结构是什么(并且希望保持灵活性),我将成对弹出值和数字(x,n)
。让我们称之为标记,因此重新命名T
Tagger
,因此假设我知道您的集合类型是Coll
,那么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通过将标记函数包装在轻量级构造函数中来确保类型安全。我们需要使用数据
而不是类型
,因为我已经用n
参数化了
liftInContext :: (Functor coll,Num n) => (coll x -> x -> n) -> coll x -> coll (x,n)
liftInContext rankfunction mycoll = liftT (rankfunction mycoll) mycoll
我倾向于用类型参数(如某些语言(如Java)中的泛型)替换固定类型X
和集合类型Coll
,以提高代码重用:
data (Functor coll,Num n) => Tagger coll x n = Tgr (coll x -> coll (x,n))
现在我们坚持认为,coll
section类型是一个函子,因此我们可以使用fmap
将函数点式应用于集合(在您的情况下至关重要,任何集合类型都将是函子的一个实例)
我对你的T
的Tagger
的定义非常满意,但是如果你只有coll
、x
和n
的一种可能性,你可以使用CollTaggerXInt
liftInContext :: (Functor coll,Num n) => (coll x -> x -> n) -> coll x -> coll (x,n)
liftInContext rankfunction mycoll = liftT (rankfunction mycoll) mycoll
U形标记器
你的U
类型是f
fmap :: Functor f => (a -> b) -> f a -> f b
liftT :: (Functor coll,Num n) => (x -> n) -> coll x -> coll (x,n)
liftT f = fmap tag where
tag x = (x,f x)
liftInContext :: (Functor coll,Num n) => (coll x -> x -> n) -> coll x -> coll (x,n)
liftInContext rankfunction mycoll = liftT (rankfunction mycoll) mycoll