1

Let's take the following filter function:

#lang sicp

(define (filter function sequence)
  (if (null? sequence)
      nil
      (let ((elem (car sequence)) (rest (cdr sequence)))
        (if (function elem)
            (cons elem (filter function rest))
            (filter function rest)))))

(filter (lambda (x) (> x 3)) '(1 2 3 4 5))

Is the following the correct way to convert it to a curried function?

(define filter2
  (lambda (function)
    (lambda (sequence)
      (if (null? sequence)
          nil
          (let ((elem (car sequence)) (rest (cdr sequence)))
            (if (function elem)
              (cons elem ((filter2 function) rest))
              ((filter2 function) rest)))))))

That is, the two differences being:

  • Definition: Instead of calling it defining it as (define func arg1 arg2 ...) it turns into (define func (lambda (arg1) (lambda (arg2) (... ))).
  • Calling: Instead of calling it as (func arg1 arg2 ...) it turns into (((func arg1) arg2) ...).

Are there any other differences, or it's more like syntactic sugar / differences in parens when doing the two?

Wojciech Gac
  • 1,538
  • 1
  • 16
  • 30
David542
  • 104,438
  • 178
  • 489
  • 842
  • You may enjoy going through [this exercise](https://www.cs.toronto.edu/~david/csc324/exercises/ex3/handout.html), which gives a good idea of how currying is implemented in general. – mindthief Jun 16 '21 at 00:52
  • 1
    @mindthief thanks for sharing, that's pretty neat. How'd you find that? – David542 Jun 16 '21 at 01:27
  • 1
    I don't recall now as it was a while ago, but I remember it being helpful. The rest of the course materials for that class also looked great! – mindthief Jun 16 '21 at 23:09

1 Answers1

2

Yes, your double lambda approach does work. But there are nicer ways to do this too.

It turns out define can do this directly. The following two pieces of code are identical:

(define f
  (lambda (x)
    (lambda (y)
      (+ x y)))

and

(define ((f x) y)
  (+ x y))

Applying this to your example above, we get:

(define ((filter function) sequence)
  (if (null? sequence)
      nil
      (let ((elem (car sequence)) (rest (cdr sequence)))
        (if (function elem)
            (cons elem (filter function rest))
            (filter function rest)))))

((filter (lambda (x) (> x 3))) '(1 2 3 4 5))

Additionally if you have an existing function you'd like to turn into a curried variant, the racket/function module provides curry:

(require racket/function)

(define (f a b)
   (+ 1 2))

(((curry f) 1) 2)
Leif Andersen
  • 21,580
  • 20
  • 67
  • 100
  • thanks that's so neat. So the following two forms are equivalent? `(define ((filter function) sequence) (...` and `(define filter (lambda (function) (lambda (sequence) (...` ? – David542 Jun 16 '21 at 23:54
  • Or maybe a clearer way would be to say `(define ((add1 a) b) (+ a b))` == `(define add2 (lambda (a) (lambda (b) (+ a b))))` ? – David542 Jun 16 '21 at 23:57
  • 1
    You are correct, they are identical. In fact, if you type them into DrRacket, click on the `Macro Stepper` button (top right), set macro hiding (bottom left) to `disable`, you'll see that they even expand to the exact same code. :) – Leif Andersen Jun 17 '21 at 00:21
  • cool. Inspired by the latter part of your answer, I asked a new question that's related to making a curried function if interested in taking a look: https://stackoverflow.com/questions/68011489/how-to-create-a-make-curry-function-like-racket-has. – David542 Jun 17 '21 at 00:33