# Break out of the cycle. What's the Racket way alternative?

**URL:** https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814
**Category:** Questions & Answers
**Created:** [March 20, 2024, 5:14pm UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814 "2024-03-20T17:14:22Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![Tyrn](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/tyrn/32/1731_2.png) [@Tyrn](https://racket.discourse.group/u/Tyrn)
#### Post date: [March 20, 2024, 5:14pm UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/1 "2024-03-20T17:14:22Z")

</div>

Hi,

Iterating through a string is a piece of cake:

```scheme
(for ([c "Hello"])
    (display c)
    (newline))

```

Even in a more sophisticated way:

```scheme
 (define (list-chars str)
    (for ([c str]
          [i (in-naturals)])
      (printf "~a: ~a\n" i c)))

```

Almost what I need. What I need actually:

- Input: a nonempty string of characters without spaces
- Output: a prefix of the input string defined as follows:  
- First character goes into the prefix regardless of case  
- If the next character is lowercase, it goes to the prefix  
- If the next character is uppercase, it goes to the prefix, and the prefix is done and returned.

It should work like this:  
`alfa` -\> `alfa`  
`Alfa` -\> `Alfa`  
`DiCAp` -\> `DiC`  
`BRaVo` -\> `BR`  
`b` -\> `b`  
`B` -\> `B`  
...  
No big deal, if you can break out of the cycle. I can't even see how things like drop while may help.

---

<div class="post-metadata">

### Author: ![EmEf](https://avatars.discourse-cdn.com/v4/letter/e/53a042/32.png) [@EmEf](https://racket.discourse.group/u/EmEf)
#### Post date: [March 20, 2024, 5:41pm UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/2 "2024-03-20T17:41:55Z")

</div>

```scheme
#lang racket

#; {String -> String}
(define (prefix str)
  (let/ec return
    (define char* (string->list str))
    (for/fold ([result (~a (first char*))]) ([c (rest char*)])
      (cond
        [(char-upper-case? c) (return (~a result c))]
        [(char-lower-case? c) (~a result c)]
        [else result]))))

(define examples
  '[(alfa alfa)
    (Alfa Alfa)
    (DiCAp DiC)
    (BRaVo BR)
    (b b)
    (B B)])

(require rackunit)

(for-each (λ (x) (check-equal? (prefix (~a (first x))) (~a (second x)))) examples)

```

---

<div class="post-metadata">

### Author: ![EmEf](https://avatars.discourse-cdn.com/v4/letter/e/53a042/32.png) [@EmEf](https://racket.discourse.group/u/EmEf)
#### Post date: [March 20, 2024, 5:53pm UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/3 "2024-03-20T17:53:30Z")

</div>

The following is better: (1) it’s functional and doesn’t rely on a control effect and (2) it probably deals with large strings better because string-append (in ~a) can get expensive when strings get long.

```scheme
#; {String -> String}
(define (prefix str)
  (define char* (string->list str))
  (let while ([char* (rest char*)] [result (list (first char*))])
    (cond
      [(empty? char*) (list->string (reverse result))]
      [else 
       (define c (first char*))
       (cond
         [(char-upper-case? c) (list->string (reverse (cons c result)))]
         [(char-lower-case? c) (while (rest char*) (cons c result))]
         [else #;unspecified: (while (rest char*) result)])])))

(define examples
  '[(alfa alfa)
    (Alfa Alfa)
    (DiCAp DiC)
    (BRaVo BR)
    (b b)
    (B B)])

(require rackunit)

(for-each (λ (x) (check-equal? (prefix (~a (first x))) (~a (second x)))) examples)

```

---

<div class="post-metadata">

### Author: ![sorawee](https://avatars.discourse-cdn.com/v4/letter/s/ea5d25/32.png) [@sorawee](https://racket.discourse.group/u/sorawee)
#### Post date: [March 20, 2024, 6:07pm UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/4 "2024-03-20T18:07:08Z")

</div>

Here’s another solution, using `for`‘s `#:final`, which is less general than `let/ec`, but happens to fit the task. I also use `cons` to accumulate results in constant time.

```scheme
#; {String -> String}
(define (prefix str)
  (define char* (string->list str))
  (for/fold ([result (list (first char*))]
             #:result (list->string (reverse result)))
            ([c (in-list (rest char*))])
    #:final (char-upper-case? c)
    (cons c result)))

```

---

<div class="post-metadata">

### Author: ![jbclements](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/jbclements/32/11_2.png) [@jbclements](https://racket.discourse.group/u/jbclements)
#### Post date: [March 20, 2024, 7:46pm UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/5 "2024-03-20T19:46:29Z")

</div>

I think I'm going to call this the HtDP approach? You presented it as a state machine, so I wrote it as a state machine with two states, the initial state and the continue state.

```scheme
;; the initial state
(define (prefix str)
  ;; string is nonempty, so we can definitely advance to character 1
  (prefix-continue str 1))

;; given a string and the position of the first unexamined character,
;; return the prefix that matches the specification.
(define (prefix-continue str posn)
  (cond [(<= (string-length str) posn)
         ;; string is over, return it:
         str]
        [else
         (match (string-ref str posn)
           [(? char-upper-case?) (substring str 0 (add1 posn))] ; stop
           [(? char-lower-case?) (prefix-continue str (add1 posn))] ; continue
           [other (error 'abbrev-continue "unexpected character: ~v" other)])]))

(define examples
  '[(alfa alfa)
    (Alfa Alfa)
    (DiCAp DiC)
    (BRaVo BR)
    (b b)
    (B B)])

(require rackunit)

(for-each (λ (x) (check-equal? (prefix (~a (first x))) (~a (second x)))) examples)

```

---

<div class="post-metadata">

### Author: ![shawnw](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/shawnw/32/1031_2.png) [@shawnw](https://racket.discourse.group/u/shawnw)
#### Post date: [March 21, 2024, 3:16am UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/6 "2024-03-21T03:16:34Z")

</div>

Are regular expressions allowed?

```scheme
#lang racket/base

(define (make-prefix s)
  (car (regexp-match #px"^.[[:lower:]]*[[:upper:]]?" s)))

(module+ test
  (require rackunit)
  (check-equal? (make-prefix "alfa") "alfa")
  (check-equal? (make-prefix "Alfa") "Alfa")
  (check-equal? (make-prefix "DiCap") "DiC")
  (check-equal? (make-prefix "BRaVo") "BR")
  (check-equal? (make-prefix "b") "b")
  (check-equal? (make-prefix "B") "B"))

```

---

<div class="post-metadata">

### Author: ![Tyrn](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/tyrn/32/1731_2.png) [@Tyrn](https://racket.discourse.group/u/Tyrn)
#### Post date: [March 21, 2024, 8:09am UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/7 "2024-03-21T08:09:38Z")

</div>

Everything's allowed! Unfortunately, it won't work (?) with Unicode, but it isn't your fault.

This example shows that there's nothing like the right tool for the task.

---

<div class="post-metadata">

### Author: ![Tyrn](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/tyrn/32/1731_2.png) [@Tyrn](https://racket.discourse.group/u/Tyrn)
#### Post date: [March 21, 2024, 8:33am UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/8 "2024-03-21T08:33:54Z")

</div>

Amazing display, well beyond my expectations! Thank you very much!

A lot of material to study. A sad point: even after reading this or that, the Racket Guide including, I discover important bits and pieces I never _seen_ before. Much less tinkered with.

---

<div class="post-metadata">

### Author: ![Tyrn](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/tyrn/32/1731_2.png) [@Tyrn](https://racket.discourse.group/u/Tyrn)
#### Post date: [March 21, 2024, 8:40am UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/9 "2024-03-21T08:40:06Z")

</div>

What's `#;unspecified:` ? It has something to do with the Typed Racket? What do you call such decorations?

Google isn't particularly helpful in this case.

---

<div class="post-metadata">

### Author: ![sorawee](https://avatars.discourse-cdn.com/v4/letter/s/ea5d25/32.png) [@sorawee](https://racket.discourse.group/u/sorawee)
#### Post date: [March 21, 2024, 9:18am UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/10 "2024-03-21T09:18:53Z")

</div>

It’s an [S-expression comment](https://racket.discourse.group/t/nested-split-map-join-preferred-style/2809/6). Here, only `unspecified:` is commented, but the rest of the code ( `(while (rest char*) result)` … ) is not.

---

<div class="post-metadata">

### Author: ![Tyrn](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/tyrn/32/1731_2.png) [@Tyrn](https://racket.discourse.group/u/Tyrn)
#### Post date: [March 21, 2024, 9:45am UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/11 "2024-03-21T09:45:54Z")

</div>

What does `unspecified:` mean?

---

<div class="post-metadata">

### Author: ![sorawee](https://avatars.discourse-cdn.com/v4/letter/s/ea5d25/32.png) [@sorawee](https://racket.discourse.group/u/sorawee)
#### Post date: [March 21, 2024, 10:09am UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/12 "2024-03-21T10:09:03Z")

</div>

You are reading too much into this. It’s not a programming construct. It’s just a “textual comment”, saying that you have not specified what should be done in that case. You wrote:

> Input: a nonempty string of characters without spaces  
> Output: a prefix of the input string defined as follows:
> 
> - First character goes into the prefix regardless of case
> - If the next character is lowercase, it goes to the prefix
> - If the next character is uppercase, it goes to the prefix, and the prefix is done and returned.

But this specification is incomplete. What if the next character is a number -- what should happen? Matthias didn’t know what should be done, so he left a comment saying that he’s implementing that case in a way that makes sense to him, but might not be what you ultimately want if/when you refine your specification. He was trying to be concise by using the S-expression comment there, but if that causes so much confusion, perhaps this might help?

```scheme
(define (prefix str)
  (define char* (string->list str))
  (let while ([char* (rest char*)] [result (list (first char*))])
    (cond
      [(empty? char*) (list->string (reverse result))]
      [else 
       (define c (first char*))
       (cond
         [(char-upper-case? c) (list->string (reverse (cons c result)))]
         [(char-lower-case? c) (while (rest char*) (cons c result))]
         [else 
          ;; This case is unspecified in the problem statement. 
          ;; Here, we just ignore the character
          (while (rest char*) result)])])))

```

EDITED: the else case ignores the char, not treating it like lower case.

---

<div class="post-metadata">

### Author: ![bakgatviooldoos](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/bakgatviooldoos/32/1381_2.png) [@bakgatviooldoos](https://racket.discourse.group/u/bakgatviooldoos)
#### Post date: [March 21, 2024, 10:15am UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/13 "2024-03-21T10:15:43Z")

</div>

As an aside to this, I am partial to using the `sexpr` comments to help me remember non-keyword arguments that might not be obvious at first--a habit which I picked up from reading other people's code:

```scheme
(and (close-ports) (subprocess-kill sp #;force? #true))
(bytes->string/utf-8 (read-bytes bytes-count out) #;err-char=� #\uFFFD)
(play-sound path:ding-off #;asyn? #true)

```

It's such a nice feature, and it has the added benefit of the _visual_ symmtery with `#:`.

---

<div class="post-metadata">

### Author: ![shawnw](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/shawnw/32/1031_2.png) [@shawnw](https://racket.discourse.group/u/shawnw)
#### Post date: [March 21, 2024, 3:06pm UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/14 "2024-03-21T15:06:02Z")

</div>

Huh, TIL character classes in regular expressions don't cover the full range of Unicode codepoints. Using properites works, though; changing the regular expression in the above to ` #px"^.\\p{Ll}*\\p{Lu}?"` makes `(make-prefix "ÄbéĒf")` return `"ÄbéĒ"`.

(At lest, until you get into multi-codepoint extended grapheme clusters like when dealing with combinining characters; Racket's regular expressions don't have an atom to match one of those like perl's `\X`. Hmm. Maybe I should work on a PCRE2 binding library...)

---

<div class="post-metadata">

### Author: ![Tyrn](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/tyrn/32/1731_2.png) [@Tyrn](https://racket.discourse.group/u/Tyrn)
#### Post date: [March 21, 2024, 5:37pm UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/15 "2024-03-21T17:37:43Z")

</div>

Fantastic, just the same! Almost unbelievable.

---

<div class="post-metadata">

### Author: ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)
#### Post date: [March 21, 2024, 7:06pm UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/16 "2024-03-21T19:06:05Z")

</div>

> Maybe I should work on a PCRE2 binding library...

Why not improve the Racket implementation?

---

<div class="post-metadata">

### Author: ![shawnw](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/shawnw/32/1031_2.png) [@shawnw](https://racket.discourse.group/u/shawnw)
#### Post date: [March 22, 2024, 6:23pm UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/17 "2024-03-22T18:23:49Z")

</div>

> [@soegaard](#):
>
> Why not improve the Racket implementation?

There are so many things that PCRE regular expression dialect supports that Racket ones don't that it's easier to just use it than trying to reimplement everything I want in a codebase I'm not familiar with.

---

<div class="post-metadata">

### Author: ![damien\_mattei](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/damien_mattei/32/2706_2.png) [@damien\_mattei](https://racket.discourse.group/u/damien_mattei)
#### Post date: [March 23, 2024, 9:05am UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/18 "2024-03-23T09:05:06Z")

</div>

note that , the input does not seems to be string in above code, an exact code is:

```scheme
#lang racket
#; {String -> String}
(define (prefix str)
  (define char* (string->list str))
  (let while ([char* (rest char*)] [result (list (first char*))])
    (cond
      [(empty? char*) (list->string (reverse result))]
      [else 
       (define c (first char*))
       (cond
         [(char-upper-case? c) (list->string (reverse (cons c result)))]
         [(char-lower-case? c) (while (rest char*) (cons c result))]
         [else #;unspecified: (while (rest char*) result)])])))

(define examples
  '[("alfa" "alfa")
    ("Alfa" "Alfa")
    ("DiCAp" "DiC")
    ("BRaVo" "BR")
    ("b" "b")
    ("B" "B")])

;;(require rackunit)

(for-each (λ (x)
            (display (prefix (first x)))
            (display " ")
            (display (second x))
            (newline)) examples)

```

result:

```scheme
Welcome to DrRacket, version 8.11 [cs].
Language: racket, with debugging; memory limit: 8192 MB.
alfa alfa
Alfa Alfa
DiC DiC
BR BR
b b
B B

```

---

<div class="post-metadata">

### Author: ![Tyrn](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/tyrn/32/1731_2.png) [@Tyrn](https://racket.discourse.group/u/Tyrn)
#### Post date: [March 23, 2024, 9:27am UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/19 "2024-03-23T09:27:14Z")

</div>

Will you please point out the difference? Just for convenience.

---

<div class="post-metadata">

### Author: ![damien\_mattei](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/damien_mattei/32/2706_2.png) [@damien\_mattei](https://racket.discourse.group/u/damien_mattei)
#### Post date: [March 23, 2024, 9:34am UTC](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814/20 "2024-03-23T09:34:45Z")

</div>

just that in the code given as solution the input are quoted symbol ,example alfa not string "alfa", try this and you will see it cause an error:

```scheme
Welcome to DrRacket, version 8.11 [cs].
Language: racket, with debugging; memory limit: 8192 MB.
> (prefix (first (first examples)))
. . string->list: contract violation
  expected: string?
  given: 'alfa

```

but why it doen not cause an error ,i do not really know , but i suppose rackunit and check-equal? encapsulate the error, but i'm not sure!

but the algorithm is perfectly valid, this is a minor bug.

[Next page](https://racket.discourse.group/t/break-out-of-the-cycle-whats-the-racket-way-alternative/2814.md?page=2)
