Algorithm SBCL Lisp在运行时将类型输入到内部循环。我如何覆盖这个?

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

我实现了一个项目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 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))