代码之家  ›  专栏  ›  技术社区  ›  7stud

为什么是传单和封页?

  •  1
  • 7stud  · 技术社区  · 9 月前

    我使用定义了一个局部递归函数 flet .递归函数计算阶乘:

     (flet ((my-fac (n)
               (cond ((= n 1) 1)
                     (t (* n (my-fac (1- n)))))))
    

    然后我用 mapcar 申请 my-fac 到列表的每个元素以生成阶乘列表:

    (defun my-mapping (lst x)
      (flet ((my-fac (n)
               (cond ((= n 1) 1)
                     (t (* n (my-fac (1- n)))))))
        (mapcar #'my-fac lst)))
    

    请注意中未使用的第二个参数变量 my-mapping 释义以下是结果:

    CL-USER> (my-mapping '(1 2 3 4) 1)
    (1 2 6 24)
    

    接下来,我更改了 我的地图 函数来使用第二个参数变量:

    (defun my-mapping (lst x)
      (flet ((my-fac (n)
               (cond ((= n 1) x) ; <==========CHANGE HERE
                     (t (* n (my-fac (1- n)))))))
        (mapcar #'my-fac lst)))
    

    由于这一变化,我打电话时预料到了 (my-mapping '(1 2 3 4) 2) ,结果将是乘2的阶乘。因此,与其得到先前的结果:

      (1 2 6 24)
    

    我期望得到:

      (2 4 12 48)
    

    这是我的实际结果

    CL-USER> (my-mapping '(1 2 3 4) 2) 
    (2 2 6 24)
    

    在我看来 我的fac 已获取的值 x 当计算1(列表中的第一个元素)的阶乘时,但对于列表中的其他元素,它看起来像 x 不知何故,其值为1。

    1 回复  |  直到 9 月前
        1
  •  2
  •   Rainer Joswig Michael Fox    9 月前

    有两种方法可以定义本地函数: FLET LABELS .

    有关的规格,请参阅CL Hyperspec FLET and LABELS .

    关于FLET:

    名称绑定的范围仅包括正文。在 的主体 flet ,函数名称与定义的名称匹配 传单 提到 局部定义的函数,而不是全局函数 相同名称的定义。

    上面写着 标签 :

    labels 相当于 传单 除了定义的范围 的函数名称 标签 包含函数定义 他们自己以及身体。

    方法

    (flet ((my-local-function ()
             ...))  ; <- my-local-function CAN'T be used here
    
      ; my-local-function can be used in the body:
      (my-local-function))
    
    (labels ((my-local-function ()
             ...))  ; <- my-local-function can be used here
    
      ; my-local-function can be used in the body :
      (my-local-function))
    

    标签 用于递归函数。

    您正在使用 传单 ,这行不通。

    (defun my-mapping (lst x)
      (flet ((my-fac (n)
               (cond ((= n 1) x) 
                     (t (* n (my-fac (1- n)))))))  ; <- problem
        (mapcar #'my-fac lst)))                    ; <- no problem
    

    在上面的函数中,对的递归调用 MY-FAC 是不可能的。 传单 不允许自递归调用。您正在调用一个名为的全局函数 MY-FAC 。你需要有这样一个函数,才能使上面的代码工作。我怀疑这是以前实验中定义的情况。

    实际调用本地递归函数替换 传单 具有 标签 :

    CL-USER 16 > (defun my-mapping (lst x)
                   (labels ((my-fac (n)
                              (cond ((= n 1) x)
                                    (t (* n (my-fac (1- n)))))))
                     (mapcar #'my-fac lst)))
    MY-MAPPING
    
    CL-USER 17 > (my-mapping '(1 2 3 4) 2)
    (2 4 12 48)
    

    以上说明了一个人得到了预期的结果。

    有问题的代码和Lisp编译器

    例如,这就是LispWorks编译器所说的:

    CL-USER 18 > (defun my-mapping (lst x)
                   (flet ((my-fac (n)
                            (cond ((= n 1) 1)
                                  (t (* n (my-fac (1- n)))))))
                     (mapcar #'my-fac lst)))
    MY-MAPPING
    
    CL-USER 19 > (compile *)
    ;;;*** Warning in MY-MAPPING: X is bound but not referenced
    
    The following function is undefined:
    MY-FAC which is referenced by MY-MAPPING
    

    SBCL表示:

    ; in: DEFUN MY-MAPPING
    ;     (SB-INT:NAMED-LAMBDA MY-MAPPING
    ;         (LST X)
    ;       (BLOCK MY-MAPPING
    ;         (FLET ((MY-FAC #
    ;                  #))
    ;           (MAPCAR #'MY-FAC LST))))
    ; 
    ; caught STYLE-WARNING:
    ;   The variable X is defined but never used.
    ; in: DEFUN MY-MAPPING
    ;     (MY-FAC (1- N))
    ; 
    ; caught STYLE-WARNING:
    ;   undefined function: COMMON-LISP-USER::MY-FAC
    ; 
    ; compilation unit finished
    ;   Undefined function:
    ;     MY-FAC
    ;   caught 2 STYLE-WARNING conditions