首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从咖喱-0,1,2,到...n

从咖喱-0,1,2,到...n
EN

Stack Overflow用户
提问于 2021-06-17 03:44:47
回答 3查看 286关注 0票数 1

接着我问了一个关于写咖喱函数的问题,如何创建一个像球拍一样的制作咖喱功能,我已经开始为0,1,2写固定的大小写了--它们和教堂数字非常相似,非常简洁。以下是我到目前为止所拥有的:

代码语言:javascript
复制
(define (curry-0 func)
  func)

(define hello (begin (display "Hello!") (newline)))
(curry-0 hello)
; Hello!
代码语言:javascript
复制
(define (curry-1 func)
  (lambda (x)
      (func x )))

((curry-1 -) 2)
; -2
代码语言:javascript
复制
(define (curry-2 func)
  (lambda (x)
    (lambda (y)
      (func x y))))

(((curry-2 +) 2) 3)
5

其模式似乎是:

代码语言:javascript
复制
(define curry-n func
     (lambda (x1)
        (lambda (x2)
           ...
            (lambda (xn)
                (func x1 x2 ... xn)

然而,我在“构建”n-嵌套lambda表达式时遇到了一些困难。我想我可以构建一个嵌套的lambda,如下所示:

代码语言:javascript
复制
(define (curry-n num func)
     (if (num > 0)
         (lambda (?) (curry-n (- num 1) func))))

但我不确定如何将变量“绑定”到每个lambda函数,也不确定如何将这些相同的变量(按顺序)传递给(func x1 x2 ... xn)函数。

这是不正确的,但我从……开始。

代码语言:javascript
复制
(define (curry-n num func)
 (if (> num 0)
      ; but lambda won't accept a number, possible to string-format?
      (curry-n (- num 1) (lambda (num)))))

这是怎么做到的呢?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2021-06-17 05:15:02

使用循环

你需要一些looplambda收集每一个arg -

代码语言:javascript
复制
(define (curry-n num f)
  (let loop
    ((n num)
     (args null))
    (lambda ((arg null))
      (cond ((= n 0)
             (apply f (reverse args)))
            ((= n 1)
             (apply f (reverse (cons arg args))))
            (else
             (loop (- n 1) (cons arg args)))))))

curry应该始终返回一个过程,因此您可以看到loop总是返回一个lambda,甚至对于num = 0情况也是如此。每个arg都是consd到args上,创建了一个相反的参数列表,这就是为什么我们在对用户提供的过程f进行apply之前,先对args进行reverse

就像这样-

代码语言:javascript
复制
(define (hello)
  (println "hello world"))

((curry-n 0 hello))
代码语言:javascript
复制
"hello world"
代码语言:javascript
复制
((((curry-n 3 +) 10) 20) 30)
代码语言:javascript
复制
60

使用分隔延续的

本着分享学习练习的精神,请花一些时间使用定界延续 -

代码语言:javascript
复制
(require racket/control)

(define (curry-3 f)
  (reset (f (shift k k) (shift k k) (shift k k))))

(define (hello a b c)
  (printf "hello world ~a ~a ~a\n" a b c))

((((curry-3 hello) 10) 20) 30)
代码语言:javascript
复制
hello world 10 20 30

要获得curry-n,我们所需要做的就是构建一个n延续列表!

代码语言:javascript
复制
(require racket/control)

(define (curry-n n f)
  (reset (apply f (build-list n (lambda (_) (shift k k))))))

就像我们的第一次一样-

代码语言:javascript
复制
(define (hello a b c)
  (printf "hello world ~a ~a ~a\n" a b c))

((((curry-n 3 hello) 10) 20) 30)
代码语言:javascript
复制
"hello world 10 20 30"
代码语言:javascript
复制
((((((curry-n 5 +) 10) 20) 30) 40) 50)
代码语言:javascript
复制
150

您可以将这个过程形象化为这样的工作,其中每个__都是一个需要填充的“洞”-

代码语言:javascript
复制
(f __ __ __)
    \
     \_ (lambda (x)
          (f x __ __))
                \
                 \_ (lambda (y)
                      (f x y __))
                              \
                               \_ (lambda (z)
                                    (f x y z))

唯一的区别是有n洞要填充,所以我们构建了一个n孔和apply的列表-

代码语言:javascript
复制
(build-list 3 (lambda (_) (shift k k)))
代码语言:javascript
复制
(list __
       \
        \_ (lambda (x)
              (list x __
                       \
                        \_ (lambda (y)
                             (list x y __
                                        \
                                         \_ (lambda (z)
                                              (list x y z))
代码语言:javascript
复制
(apply f (list x y z)

方案

我没注意到你在计划里做这件事。我们可以定义build-list -

代码语言:javascript
复制
(define (build-list n f)
  (let loop
    ((m 0))
    (if (>= m n)
        '()
        (cons (f m) (loop (+ m 1))))))

我们可以使用Olivier最初的移位/复位实现,

代码语言:javascript
复制
(define-syntax reset
  (syntax-rules ()
    ((_ ?e) (reset-thunk (lambda () ?e)))))

(define-syntax shift
  (syntax-rules ()
    ((_ ?k ?e) (call/ct (lambda (?k) ?e)))))

(define *meta-continuation*
  (lambda (v)
    (error "You forgot the top-level reset...")))

(define abort
  (lambda (v)
    (*meta-continuation* v)))

(define reset-thunk
  (lambda (t)
    (let ((mc *meta-continuation*))
      (call-with-current-continuation
        (lambda (k)
      (begin
        (set! *meta-continuation* (lambda (v)
                    (begin
                      (set! *meta-continuation* mc)
                      (k v))))
        (abort (t))))))))

(define call/ct
  (lambda (f)
    (call-with-current-continuation
      (lambda (k)
    (abort (f (lambda (v)
            (reset (k v)))))))))

我们的curry-n可以保持原样-

代码语言:javascript
复制
(define (curry-n n f)
  (reset (apply f (build-list n (lambda (_) (shift k k))))))

((((((curry-n 5 +) 10) 20) 30) 40) 50)
代码语言:javascript
复制
150
票数 1
EN

Stack Overflow用户

发布于 2021-06-17 05:40:06

其他答案可能会更有效率,因为它们积累了一个具体的参数列表,或者更有吸引力,因为它们允许你一次接受多个参数,但在我看来,一个更好的学习练习,也更简单,就是编写一个基本函数,每次只使用一个参数,而不需要累加器。

代码语言:javascript
复制
(define (curry n f)
  (cond ((= n 1) f)
        (else (lambda (x)
                (curry (- n 1)
                       (lambda args
                          (apply f (cons x args))))))))

 > (((curry 2 +) 5) 4)
=> 9

而不是累积参数,我们只是创建一个新的lambda,它每次都期望更少的参数,并对其进行改进。它的行为非常类似于您对固定n的尝试的推广。这和rawrex的(完全合理的)答案是一样的基本方法,但是没有处理更大块的args的花哨工具。

票数 2
EN

Stack Overflow用户

发布于 2021-06-17 04:46:37

我建议您编写以下函数:

代码语言:javascript
复制
;; create `num` nested lambdas, where the body applies `func` to
;; `args-so-far` along with the arguments of those nested lambdas
(define (curry-n* func num args-so-far)
  ...)

以下是它的用法:

代码语言:javascript
复制
(define (sub-4 a b c d)
  (- a b c d))

(curry-n* sub-4 0 (list 10 1 2 3)) 
;=> should evaluate to 10 - 1 - 2 - 3 = 4

(curry-n* sub-4 1 (list 10 1 2)) 
;=> should evaluate to a procedure that accepts x, 
;   and returns 10 - 1 - 2 - x = 7 - x

(curry-n* sub-4 2 (list 10 1)) 
;=> should evaluate to a procedure that accepts x, 
;   and returns a procedure that accepts y, 
;   and returns 10 - 1 - x - y = 9 - x - y

对于基本情况(num = 0),您需要使用函数apply

一旦您拥有了curry-n*,您就可以创建curry-n,该curry-ncurry-n*作为一个辅助函数调用。

一旦你有了解决方案,你会注意到它不是很有效。您可以修改curry-n*以翻转args-fo-far,使其用法如下:

代码语言:javascript
复制
(define (sub-4 a b c d)
  (- a b c d))

(curry-n* sub-4 0 (list 3 2 1 10)) 
;=> should evaluate to 4

(curry-n* sub-4 1 (list 2 1 10)) 
;=> should evaluate to a procedure that accepts x, 
;   and returns 7 - x

(curry-n* sub-4 2 (list 1 10)) 
;=> should evaluate to a procedure that accepts x, 
;   and returns a procedure that accepts y, 
;   and returns 9 - x - y
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68012640

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档