【问题标题】:output of map function?地图功能的输出?
【发布时间】:2022-01-11 09:23:13
【问题描述】:

您好,我正在尝试理解以下代码的输出

(define p (lambda (x) (lambda (y) (x (x y)))))
(define q (lambda (x) (* x x))) 

当我使用时

(map (p q) (list 1 2 3)) 

结果是

(1 16 81)

答案不应该是

(1 4 9) ?

【问题讨论】:

  • (map q (list 1 2 3)) 肯定会返回。但是(p q)q 不同,所以你会得到不同的结果。尝试弄清楚(p q) 的含义。

标签: scheme racket brackets


【解决方案1】:

提供了两个功能:

(define p (lambda (x) (lambda (y) (x (x y)))))
(define q (lambda (x) (* x x))) 

q 是一个函数,它接受一个数字并将其平方。 p 是一个函数,它接受一个函数x,并返回另一个函数,其中x 两次应用于y。请注意,在p 中,x 位于表单的函数位置,并已在列表中突出显示以显示这一点。

不幸的是,x 在这两个表达式中的使用令人困惑。您可以将 lambda 表达式中的任何变量替换为任何其他变量,例如 function - 这称为 alpha-conversion - https://en.wikipedia.org/wiki/Lambda_calculus - 您可以将任何命名函数的名称更改为更合理的名称。因此,我将平方函数 q 重命名为 square,并将 p 重命名为 do-twice

(define do-twice (lambda (function) (lambda (y) (function (function y)))))
(define square (lambda (x) (* x x))) 

当您评估 do-twice square 时,发生的事情就会变得很明显。

【讨论】:

    【解决方案2】:

    您正在将(p q) 映射到列表上,所以首先要弄清楚它是什么。

    使用代入法,你得到

        (p q)
    ==> ((lambda (x) (lambda (y) (x (x y)))) q)
    ==> (lambda (y) (q (q y)))
    ==> (lambda (y) (q ((lambda (x) (* x x)) y)))
    ==> (lambda (y) (q (* y y)))
    ==> (lambda (y) ((lambda (x) (* x x)) (* y y)))
    ==> (lambda (y) (* (* y y) (* y y)))
    

    所以(p q) 是一个函数,它接受一个数字并将其平方。

    【讨论】:

      【解决方案3】:

      Francis King 的answer 很清楚, 这只是一个受其启发的扩展脚注。

      用助记符替换标识符(将q重写为square)可以更容易理解代码[1]

      Procedures as [first-class] values in Scheme[2] 经常用lambda的例子来介绍:

      > (define twelve 12)
      > (define square (lambda (x) (* x x)))
      > (square twelve)
      144
      >
      

      正如上面代码中的字符12 是一个数字的表示, 字符(lambda (x) (* x x)) 是过程的表示:
      (number? 12) => #t, (procedure? (lambda (x) (* x x))) => #t

      另外两个代码重写可能会有所帮助: 对过程使用“短格式”define,并注释定义 带有类型签名(参数和结果类型):

      > (define (square x) (* x x))  ;; Number -> Number
      > (square 3)
      9
      
      > (define (do-twice f x)       ;; (X -> X) X -> X
          (f (f x)))
      > (do-twice square 3)
      81
      
      > (map (lambda (x) (do-twice square x))
          '(1 2 3))
      (1 16 81)
      > 
      

      请注意,此do-twice 尚未对应问题的p: 这两次 map 的第一个参数需要:
      (map do-twice (make-list 3 square) '(1 2 3))

      映射一个列表需要一个参数的函数,所以某些东西必须产生两次 (define (do-twice x) (f (f x))) 作为它的值:

      > (define (do-twice-with f)    ;; (X -> X) -> (X -> X)
          (define (do-twice x)       ;; X -> X
            (f (f x)))
          do-twice)
      
      > ((do-twice-with square) 3)
      81
      > (map (do-twice-with square)
          '(1 2 3))
      (1 16 81)
      > 
      

      所以do-twice-with 是问题中的函数p

      do-twice-with 需要一个函数参数 (X -> X),但 X 可以是任何类型,所以:

      > (define (repeat s)           ;; String -> String
          (string-append s " " s))
      
      > ((do-twice-with repeat) "buffalo")
      "buffalo buffalo buffalo buffalo"
      

      do-twice-with 本身具有类型 (X' -> X')(其中 X' 代表 (X -> X)),所以可以 应用于自身:

      > (((do-twice-with do-twice-with) square) 3)
      43046721
        
      > (((do-twice-with do-twice-with) repeat) "buffalo")   [3]
      "buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo buffalo"
      

      ((((do-twice-with do-twice-with) do-twice-with) square) 3) 保留为 读者练习...

      [1] "Naming is perhaps the most powerful abstracting notion we have" [盖伊 L 斯蒂尔]

      [2]https://walker.cs.grinnell.edu/courses/151.sp04/readings/procedures-as-values.xhtml

      [3]https://en.wikipedia.org/wiki/Buffalo_buffalo_Buffalo_buffalo_buffalo_buffalo_Buffalo_buffalo

      【讨论】:

        猜你喜欢
        • 2020-08-11
        • 1970-01-01
        • 2020-05-27
        • 2011-06-14
        • 2013-12-31
        • 2017-01-12
        • 1970-01-01
        • 1970-01-01
        • 2021-11-10
        相关资源
        最近更新 更多