A Scheme Idiom

June 16, 2017

While I was reading some Scheme code recently, I discovered a delightful little Scheme idiom that could simplify some coding tasks. It looks like this:

> (define (make-accum n)
    (case-lambda
      (() n)
      ((m) (set! n (+ n m)) n)))
> (define a (make-accum 20))
> a
#<procedure>
> (a)
20
> (a 10)
30
> (a)
30

Variable a is a accumulator; define it to set its initial value, fetch its current value by calling it as a function, and increment it by calling it with a value. This works because function make-accum returns a function, defined by case-lambda, with a semantics that varies based on its arity: with no arguments, the function returns the value stored in the closure, and with a single argument, it increments the value stored in the closure and returns the new value. The actual value is stored inside the function closure so it is only available through the defined interface, making it “safer” in some sense. And the concept works for other data types than accumulators, as the solution page will show.

Your task is to describe a useful idiom in your favorite programming language. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Advertisement

Pages: 1 2

3 Responses to “A Scheme Idiom”

  1. mcmillhj said

    Perl has a cool idiom that was borrowed from LISP called the Schwartzian transform, named after Randal Schwartz, the first person to document its use in Perl. The basic idea is that you have a potentially expensive computation that you need to run on N elements and then you need to sort them. The Schwartzian Transform avoids recomputing the expensive computation for last passes of the sort.

    This lets you do interesting things like:

    1. Sort strings by their length

    #!perl
    
    use strict;
    use warnings;
    
    use feature qw/say/;
    
    my @strings = qw/
      eren
      mikasa
      armin
      levi
      erwin
      reiner
      ymir
      historia
      bertholdt
      pixis
    /;
    
    say join "\n",
        map  { $_->[0]             }
        sort { $a->[1] cmp $b->[1] }
        map  { [$_, length($_)]    } @strings;
    
    # eren
    # levi
    # ymir
    # armin
    # erwin
    # pixis
    # mikasa
    # reiner
    # historia
    # bertholdt
    

    2. Sort IPv4 addresses numerically

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use feature qw/say/;
    
    my @ips = qw/
       213.61.108.26
       235.94.112.131
       162.219.166.100
       26.190.195.43
       96.113.27.227
       96.112.27.227
       96.112.29.227
       96.112.29.255
       164.124.74.26
       58.5.201.175
       228.131.119.187
       191.226.212.172
       65.70.48.227
       35.214.73.61
       149.14.104.245
    /;
    
    say join "\n",
        map  { join '.', @$_ }
        sort { $a->[0] <=> $b->[0] || $a->[1] <=> $b->[1] || $a->[2] <=> $b->[2] || $a->[3] <=> $b->[3] }
        map  { [split /\./]  } @ips;
    
    # 26.190.195.43
    # 35.214.73.61
    # 58.5.201.175
    # 65.70.48.227
    # 96.112.27.227
    # 96.112.29.227
    # 96.112.29.255
    # 96.113.27.227
    # 149.14.104.245
    # 162.219.166.100
    # 164.124.74.26
    # 191.226.212.172
    # 213.61.108.26
    # 228.131.119.187
    # 235.94.112.131
    
  2. @programmingpraxis: Is this a closure? Seems I’ve seen something similar before and it was termed a closure.

  3. programmingpraxis said

    @bookofstevegraham: Yes, this is a closure. The value of the variable n is enclosed within the function, and not available to the rest of the program except through the interface defined by the function.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: