如何绕过 curry 评估其参数?

How to get around curry evaluating its arguments?

假设我有一些函数,我们称它为 get-io-data,例如从 shell 命令获取数据。现在我想要一个检查某些东西的函数:check-io-data。似乎应该是等效的定义方式最终是不同的。使用 'traditional' 定义,我得到一个函数,该函数根据评估时 (get-io-data) 的结果给出结果。但是,如果我使用 curry,我将得到一个函数,该函数取决于定义时 (get-io-data) 的结果。为了减少混淆,这里有一个例子:

使用传统定义:

(define (check-io-data x) (equal? (get-io-data) x))
...
(check-io-data 0) ;; Now (get-io-data) is being evaluated

使用咖喱:

(define check-io-data (curry equal? (get-io-data))) ;; Now (get-io-data) is being evaluated
...
(check-io-data 0)

我想我知道为什么它们不同,因为在第一种情况下,整个函数体可能以一种特殊的方式求值,因为它是一个函数体,而在第二种情况下,我定义了一些东西作为结果一个功能;并且这个函数在定义时被评估以获得实际定义并评估它必须评估参数的函数。

有没有办法做到这一点,或者只是行不通?而且从理论上讲,这两个定义不应该完全一样吗?

简单回答

语法是,

(define (check-io-data data) 
  ((curry equal?) (get-io-data) data))

讨论

因为check-io-data是单参数函数,所以必须这样定义。因为 equal? 是一个 arity = 2 的函数,所以柯里化时必须传递两个参数。

在示意图中,这个:

> (define f (lambda (x) (equal? 'curried-argument x)))
> (f 'curried-argument)
#t
> (f 1)
#f

相当于:

> (define (f x) ((curry equal?) 'curried-argument x))
> (f 'curried-argument)
#t
> (f 1)
#f

示例

#lang racket

;;; Use a generator to simulate
;;; a non-idempotent procedure
(require racket/generator)
(define get-io-data
  (infinite-generator
   (yield 1)
   (yield 2)
   (yield 3)))

(define (check-io-data x)
  ((curry equal?) (get-io-data) x))

(check-io-data 1)  ; #t
(check-io-data 1)  ; #f
(check-io-data 1)  ; #f
(check-io-data 1)  ; #t

结论

柯里化函数必须 define 自身作为函数 [即(define (name arg...)(body)) ] 来确定由 curry 创建的 lambda 的元数。