[plt-scheme] Re: Why do layman programmers care about Currying?

From: Jos Koot (jos.koot at telefonica.net)
Date: Sun Jan 4 15:29:14 EST 2009

#lang scheme

; permute : list-of-a (a a -> boolean) -> (list-of list-of-a)
; take all permutations of a list, but do not include more than one
; copy of all permutations A and B for which (andmap eq A B)

(define (permute lst eq)
 (if (null? lst) '(())
  (apply append (map (curry process-rotation eq) (rotations lst eq)))))

; rotations : list-of-a (a a -> boolean) -> (list-of list-of-a)
; take all rotations of a list, but only those with different cars.

(define (rotations lst eq)
 (let loop ((head lst) (tail '()))
   ((null? head) '())
   ((ormap (curry eq (car head)) tail)
    (loop (cdr head) (cons (car head) tail)))
     (append head (reverse tail)) ; (*)
     (loop (cdr head) (cons (car head) tail)))))))

; process-rotation : (a a -> boolean) (list-of a) -> (listof list-of a)
; cons the car of a rotation to all permutations of the cdr of that rotation.

(define (process-rotation eq rot)
 (map (curry cons (car rot)) (permute (cdr rot) eq)))

; curry : procedure any ... -> procedure
; curry from left

(define (curry fun . args)
 (lambda other-args
  (apply fun (append args other-args))))


(equal? (permute '(a a b c) eq?)
'((a a b c)
  (a a c b)
  (a b c a)
  (a b a c)
  (a c a b)
  (a c b a)
  (b c a a)
  (b a a c)
  (b a c a)
  (c a a b)
  (c a b a)
  (c b a a))) ; --> #t

(*) the reversal is not necessary, but without it the word 'rotation' would be misleading and the permutations may be listed in another order.


----- Original Message ----- 
From: "Ben Simon" <benjisimon at gmail.com>
To: <plt-scheme at list.cs.brown.edu>
Sent: Sunday, January 04, 2009 8:48 PM
Subject: [plt-scheme] Re: Why do layman programmers care about Currying?

On Jan 2, 9:57 am, "Grant Rettke" <gret... at acm.org> wrote:
> On Tue, Dec 30, 2008 at 11:44 PM, Richard Cleis <rcl... at me.com> wrote:
> > On Dec 30, 2008, at 9:12 PM, Grant Rettke wrote:
> >> Why do layman (working programmers) care about Currying? Or how are
> >> they applied in daily use to help one out?
> I don't understand the practical application of currying in Scheme, so
> I'm not asking about one or the other; the wikipedia link was just my
> going in position on trying to understand what is currying.

For me, the practical side of currying has to do with providing some
arguments to a function, while leaving others unset. The result is a
new function that takes in just the unset arguments.  This may not
sound very useful, but as the example below attempts to show, it can
actually be quite handy.

My suggestion is to read up on SRFI 26 and make it one of the standard
tools you use.

;;; ----------------------------------------------------------
#lang scheme

;; Scheme doesn't offer automatic currying, but SRFI-26 provides
;; the (cut ...) operator which gets us close enough.
(require srfi/26)

;; A function to send e-mail. This is a bogus implementation,
;; could easily be a "real" implementation
(define (send-mail smtp-host smtp-port from to subject message)
  (printf "Would have sent a message: \n")
  (printf "  SMTP server: ~a:~a\n" smtp-host smtp-port)
  (printf "  From: ~a\n" from)
  (printf "  To: ~a\n" to)
  (printf "  Subject: ~a\n" subject)
  (printf "  Message: ~a\n" message))

;; A place holder function to return a list of e-mail addresses. Used
;; for testing below.
(define (list-of-emails)
  '("foo at nowhere.com" "bar at nowhere.com" "baz at nowhere.com"))

;; Let's start currying...

;; Here we provide two arguments to our send-mail function, and leave
;; 3 unset (<> serves as a place holder). The result of this is a
;; function that takes in just  3 remaining arguments.
;; Now we can use `mailer' throughout our application and not have to
worry about providing
;; the SMTP host and port.
(define mailer (cut send-mail "mail.myhost.com" 25
"noreply at myhost.com" <> <> <>))

;; Use our mailer
(mailer "example at nowhere.com" "Hello World" "This is just a test...")

;; Let's say we want to send the same message over and over again. We
can use (cut ...) to
;; provide every argument but the to address.  Notice how we can
operate on our already curried
;; function.
(define broadcaster (cut mailer <> "A Special offer, Just For You"
"Here's a special offer, sent only to you. We promise..."))

;; Use our broadcaster
(for-each broadcaster

;; We can provide all the arguments except for a message, and turn our
;; function into a logger.
(define logger (cut mailer "logging at nowhere.com" "Log Message" <>))

;; Pretend this is some complicated function
(define (something-complicated logger)
  (logger "Starting to do something complicated...")
  (logger "Whew, and we're done."))
(something-complicated logger)
  For list-related administrative tasks:
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20090104/3db202f4/attachment.html>

Posted on the users mailing list.