是否可以编写返回其签名取决于构建器函数参数的函数的函数?
具体来说,我正在改进我写的原始递归的实现。我希望有类似工厂的函数,数字参数生成一个函数,该函数对元组或长度等于为数字参数传递的参数的列表起作用。目前我正在处理像pr 1 2 [0,5,13]
这样的案例,从原始递归的角度来看,这是一个无效的语句,在运行时通过Either
:
pr :: (Show a) => Int -> Int -> [a] -> Either String a
pr i k args
| 1 <= i && i <= k && length args == k = Right $ args!!(i-1)
| i <= 0 = Left "first argument of pr needs to be greater or equal to 1"
| k < i = Left "first argument of pr needs to be lesser or equal to the second argument"
| length args /= k = Left $ "pr expected "++(show k)++" arguments, got "++(show $ length args)++": pr "++(concat[show i, " ", show k, " ", show args])
但是我想以某种方式在编译时捕获这种情况,因为从我想要实现的正式系统的角度来看,这是一个编译时错误 - 将更多参数传递给函数而不是其域指定。
这在某种程度上是可能的,如果不是,那么什么是正确的方法来获得应该是无效语句的编译时错误。
答案 0 :(得分:5)
你想要的是一个大小的矢量。它就像一个列表,但除了它的元素类型之外,它还通过类型级自然数进行参数化。
Hackage上的 sized-vector包是您所需要的。碰巧,您尝试实现的功能是此库中的last
功能。
请注意,每次调用last
时,都必须向编译器证明其参数向量的大小至少为1.您可以通过在源代码中构造向量来实现此目的(例如,编译器)将理解1 :- 2 :- Nil
的大小为2)或者如果向量是在运行时获得的,也许是通过从列表转换获得的,那么你必须编写一个函数,如果它没有元素或者给出运行时错误,或者构造一个大小至少为1的向量,即对某些S n
具有类型级别n
。
如果您不熟悉依赖类型编程(包含此类的范例以及更多内容),我建议您先查看一些教程。例如,this post是一个很好的例子,包括如何从头开始实现向量并为它们编写函数。
谨慎,学习和使用依赖类型编程令人兴奋,令人上瘾,但也很耗时。因此,如果您想专注于手头的任务,您可能希望现在可以使用运行时检查。