0

I am trying to programmatically increment a purely alphabetical string in Scheme.

Like this "MA", then "MB" and when it reaches "MZ", it should become "MAA" and so on till "MZZ" and then it should become "MAAA" and so on.The "M" needs to be added as a prefix for the kind of work that I am doing.

I looked at this question: Incrementing alphabets and this is exactly what I want.

However, I have absolutely no idea from where to start. For starters I am not even sure how to handle ASCII in scheme. I am not expecting the whole code, but I would appreciate it if I got a few hints.

Community
  • 1
  • 1
Rohit Shinde
  • 1,575
  • 5
  • 21
  • 47

1 Answers1

2

Here's my implementation. Note that you need to load SRFI 1, which provides unfold-right:

(define letters "ABCDEFGHIJKLMNOPQRSTUVWXYZ")

(define (number->letters num)
  (unfold-right negative?
                (lambda (i) (string-ref letters (remainder i 26)))
                (lambda (i) (- (quotient i 26) 1))
                num))

(define (number->tag num)
  (list->string (cons #\M (number->letters num))))

Examples:

> (number->tag 0)
"MA"
> (number->tag 18277)
"MZZZ"
> (number->tag 18278)
"MAAAA"

The OP asked for an explanation of what the code does. So, with the understanding that the OP already understands the algorithm (since they linked to it already), what's basically left is the unfold operation.

Fold and unfold are a bit lengthy to explain and I don't want to derail this post by explaining them, but it's possible to "expand" the unfold into the equivalent loop (using the same variable names as the SRFI 1 reference implementation of unfold-right) to express what's going on:

(define (number->letters num)
  (let lp ((seed num) (ans '()))
    (if (negative? seed)
        ans
        (lp (- (quotient seed 26) 1)
            (cons (string-ref letters (remainder seed 26)) ans)))))

Basically, it builds a list, from right to left, using (string-ref letters (remainder seed 26)) each iteration (where seed is num in the initial iteration). seed's value is then updated to (- (quotient seed 26) 1) for the next iteration. The list stops when (negative? seed) is true.

You might then ask why one would use an unfold instead of the loop. Basically, in functional programming, when a "concept" can be expressed in higher-level terms (e.g., for-each, map, filter, fold, or unfold), using those terms helps other programmers understand what the code does. It's a bit like "design patterns" (as commonly used in object-oriented programming), within a functional programming context. :-)

C. K. Young
  • 219,335
  • 46
  • 382
  • 435
  • Thank you! But could you please provide me with a explanation of what the code actually does – Rohit Shinde Feb 21 '15 at 06:35
  • I've added a hopefully-simple explanation. Lemme know if there's something else you need explained. :-) – C. K. Young Feb 22 '15 at 23:44
  • I got it :) However, I would like to improve my understanding of fold and unfold and map as well. Could you provide me some links where there is a simple explanation? I am a beginner to functional programming. – Rohit Shinde Feb 23 '15 at 03:48
  • I read up on fold and map. They were pretty easy to understand. However, I am still having difficulty while understanding unfold. Could you point me to a resource. I understood your explanation of unfold. It was pretty simple :) – Rohit Shinde Feb 23 '15 at 04:35