【问题标题】:How to get around curry evaluating its arguments?如何绕过咖喱评估其论点?
【发布时间】:2025-12-19 15:00:07
【问题描述】:

假设我有一些函数,我们称它为get-io-data,例如从shell 命令获取数据。现在我想要一个检查某些东西的函数:check-io-data。似乎应该是等效的定义方式最终会有所不同。使用“传统”定义,我得到一个函数,该函数根据评估时(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)

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

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

【问题讨论】:

    标签: racket currying


    【解决方案1】:

    简单回答

    语法是,

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

    讨论

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

    以示意图的形式,这个:

    > (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 的arity。

    【讨论】: