接着我问了一个关于写咖喱函数的问题,如何创建一个像球拍一样的制作咖喱功能,我已经开始为0,1,2写固定的大小写了--它们和教堂数字非常相似,非常简洁。以下是我到目前为止所拥有的:
(define (curry-0 func)
func)
(define hello (begin (display "Hello!") (newline)))
(curry-0 hello)
; Hello!(define (curry-1 func)
(lambda (x)
(func x )))
((curry-1 -) 2)
; -2(define (curry-2 func)
(lambda (x)
(lambda (y)
(func x y))))
(((curry-2 +) 2) 3)
5其模式似乎是:
(define curry-n func
(lambda (x1)
(lambda (x2)
...
(lambda (xn)
(func x1 x2 ... xn)然而,我在“构建”n-嵌套lambda表达式时遇到了一些困难。我想我可以构建一个嵌套的lambda,如下所示:
(define (curry-n num func)
(if (num > 0)
(lambda (?) (curry-n (- num 1) func))))但我不确定如何将变量“绑定”到每个lambda函数,也不确定如何将这些相同的变量(按顺序)传递给(func x1 x2 ... xn)函数。
这是不正确的,但我从……开始。
(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)))))这是怎么做到的呢?
发布于 2021-06-17 05:15:02
使用循环
你需要一些loop从lambda收集每一个arg -
(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。
就像这样-
(define (hello)
(println "hello world"))
((curry-n 0 hello))"hello world"((((curry-n 3 +) 10) 20) 30)60使用分隔延续的
本着分享学习练习的精神,请花一些时间使用定界延续 -
(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)hello world 10 20 30要获得curry-n,我们所需要做的就是构建一个n延续列表!
(require racket/control)
(define (curry-n n f)
(reset (apply f (build-list n (lambda (_) (shift k k))))))就像我们的第一次一样-
(define (hello a b c)
(printf "hello world ~a ~a ~a\n" a b c))
((((curry-n 3 hello) 10) 20) 30)"hello world 10 20 30"((((((curry-n 5 +) 10) 20) 30) 40) 50)150您可以将这个过程形象化为这样的工作,其中每个__都是一个需要填充的“洞”-
(f __ __ __)
\
\_ (lambda (x)
(f x __ __))
\
\_ (lambda (y)
(f x y __))
\
\_ (lambda (z)
(f x y z))唯一的区别是有n洞要填充,所以我们构建了一个n孔和apply的列表-
(build-list 3 (lambda (_) (shift k k)))(list __
\
\_ (lambda (x)
(list x __
\
\_ (lambda (y)
(list x y __
\
\_ (lambda (z)
(list x y z))(apply f (list x y z)方案
我没注意到你在计划里做这件事。我们可以定义build-list -
(define (build-list n f)
(let loop
((m 0))
(if (>= m n)
'()
(cons (f m) (loop (+ m 1))))))我们可以使用Olivier最初的移位/复位实现,
(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可以保持原样-
(define (curry-n n f)
(reset (apply f (build-list n (lambda (_) (shift k k))))))
((((((curry-n 5 +) 10) 20) 30) 40) 50)150发布于 2021-06-17 05:40:06
其他答案可能会更有效率,因为它们积累了一个具体的参数列表,或者更有吸引力,因为它们允许你一次接受多个参数,但在我看来,一个更好的学习练习,也更简单,就是编写一个基本函数,每次只使用一个参数,而不需要累加器。
(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的花哨工具。
发布于 2021-06-17 04:46:37
我建议您编写以下函数:
;; 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)
...)以下是它的用法:
(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-n将curry-n*作为一个辅助函数调用。
一旦你有了解决方案,你会注意到它不是很有效。您可以修改curry-n*以翻转args-fo-far,使其用法如下:
(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 - yhttps://stackoverflow.com/questions/68012640
复制相似问题