Algorithm SBCL Lisp在运行时将类型输入到内部循环。我如何覆盖这个?
我实现了一个项目Euler问题的解决方案,使用了一种松散地基于背包问题中间相遇算法的方法。然而,SBCL——而且只有SBCL——不会编译我的解决方案 相关的代码块是:Algorithm SBCL Lisp在运行时将类型输入到内部循环。我如何覆盖这个?,algorithm,common-lisp,sbcl,Algorithm,Common Lisp,Sbcl,我实现了一个项目Euler问题的解决方案,使用了一种松散地基于背包问题中间相遇算法的方法。然而,SBCL——而且只有SBCL——不会编译我的解决方案 相关的代码块是: (loop with upper-half = <list in descending order> and lower-half = <list in ascending order> for i in lower-half maximize (loop for j on uppe
(loop with upper-half = <list in descending order>
and lower-half = <list in ascending order>
for i in lower-half maximize (loop for j on upper-half
for prod = (* (car j) i)
when (> upper-limit prod)
return (prog1 prod (setf upper-half j))))
编译器似乎假设内部循环返回Nil
(但它只返回整数;我用collect
替换最大化
)。SBCL手册对类型处理进行了一次又一次的介绍,但没有解释如何关闭这个讨厌的检查。唉,我甚至不知道这是一个bug还是一个特性。那么,我怎样才能让它工作呢
任何输入都值得赞赏。SBCL比其他一些实现做更多的静态类型检查(这是它的编译器比CCL慢很多的原因之一)。
最大化
需要内部循环的返回值为实数
,但如果当条件从未满足时,它可能返回nil
,这不是实数
。它不知道(无法证明)您实际提供的输入永远不会到达这种情况,如果您仔细想想,对于通用编译器来说,这将是一个相当了不起的壮举
其他实现可能不会检查这一点。即使在SBCL上,它也只是一个警告,但是,如果您坚持这样做,您可以忽略它,它仍然可以编译
您可以将内部循环包装在
(或…0)
中,以满足编译器的要求。也许您还可以减少安全优化旋钮以跳过此检查,但这也可能有其他影响。您可以提取内部循环并定义另一个函数,如下所示:
(defun foo (upper-half upper-limit i)
(loop
for j on upper-half
for prod = (* (car j) i)
when (> upper-limit prod)
return (prog1 prod (setf upper-half j))))
它的行为与以前不同,因为副作用只是局部的。例如,上半部分
是局部变量,而在原始代码中,它是复制表达式中的自由变量。然而,这对于类型分析并不重要
编译后,函数将具有以下类型(如descripe
所示):
备注(值t1…tn&可选)
是明确函数返回值数量的一种方式(例如,它必须精确返回n种类型)。见:
[可选的和&rest
标记]表示函数的参数列表,该函数在与值一起被赋予多值调用时,将正确接收这些值
换句话说,FOO
的返回类型是NULL
或REAL
,因为上面的REAL
根据其可能的子类型进行了扩展
NULL
类型源自NIL
值,该值可能在循环正常终止时发生
现在,您不希望在结果类型的类型联合中有一个NULL
类型。换句话说,您希望循环永远不会正常终止。这可以通过在循环结束时发出错误信号轻松实现:
(defun bar (upper-half upper-limit i)
(loop
for j on upper-half
for prod = (* (car j) i)
when (> upper-limit prod)
return (prog1 prod (setf upper-half j))
finally (error "Impossible")))
在修改后的函数中,循环的正常执行路径最终到达调用error
,其返回类型为NIL
(也称为底部类型):它从未成功返回任何值。NIL
types表示一个空域,正如人们所期望的,它是类型联合的中性元素。
因此,推断的类型为(或NIL REAL)
,即REAL
,描述修改后的函数时显示的类型:
(FUNCTION (T T T) (VALUES REAL &OPTIONAL))
如果当
条件从未满足时,它将返回NIL
。您所说的“插补类型到闭包”是什么意思?这里没有闭包。这只是一个警告,它不应该停止编译。为什么要使用FOR j ON
和(car j)
而不是FOR j IN
和j
?您可以添加类似FINALLY return 0
的内容来提供默认返回值。
(defun bar (upper-half upper-limit i)
(loop
for j on upper-half
for prod = (* (car j) i)
when (> upper-limit prod)
return (prog1 prod (setf upper-half j))
finally (error "Impossible")))
(FUNCTION (T T T) (VALUES REAL &OPTIONAL))