rnso
rnso

Reputation: 24623

Combining words list to a para in Racket

I have to combine a list of words to produce a para. I managed following:

(define (wordlist2para wl)
  (define str " ")
  (for ((w wl))
    (set! str (string-append str w " ")))
  (string-trim str))

(wordlist2para '("this" "is" "a" "test"))

Output:

"this is a test"

It works but it is not functional. How can I write functional code for this?

Upvotes: 1

Views: 127

Answers (4)

molbdnilo
molbdnilo

Reputation: 66459

If I wanted to do it explicitly and not use string-join, I would recurse and use three cases:

  • The empty list produces the empty string
  • A one-element list produces its sole element (this avoids having a trailing separator)
  • Otherwise, append the car and a space to the recursion on the cdr.

Like this:

(define (wordlist2para ws)
  (cond ((null? ws) "")
        ((null? (cdr ws)) (car ws))
        (else (string-append (car ws) " " (wordlist2para (cdr ws))))))

Upvotes: 3

rnso
rnso

Reputation: 24623

I am not sure if following can be called functional but it does use some higher order functions:

(define (wordlist2para wl)
  (string-trim 
    (apply string-append 
        (map (lambda(x) (string-append x " ")) wl))))

(wordlist2para '("this" "is" "a" "test"))

Output:

"this is a test"

Upvotes: 1

Sylwester
Sylwester

Reputation: 48775

We have standard procedures that does this:

;; racket library or srfi/13
(string-join '("this" "is" "it"))   ; ==> "this is it"

There is a way to always rewrite these that are quite simple. I'd like to step away from rackets great feature set and just focus on simple scheme with recursive procedures. Notice that in your loop you are changing 2 things wl gets smaller, str gets longer, so lets make that:

; all things that change as arguments
(define (wordlist2para-loop wl str) 
  (if (null? wl)
      str
      (wordlist2para-loop (cdr wl)
                          (string-append str (car wl) " "))))

Now for we just replace the loop:

(define (wordlist2para wl)
  (wordlist2para-loop wl ""))

From here on you can move the helper to become local or perhaps make it a named let or any other refactoring, but it doesn't really change the resulting compiled result in an implementation much, just how it looks.

Notice I haven't fixed the bug where there is only one word. (wordlist2para '("this")) ; ==> "this " The result is actually exactly the same as in your, only that it's tail recursive and functional.

Upvotes: 2

Renzo
Renzo

Reputation: 27444

No need of recursion or loop, there is the primitive function string-join for this (see the manual):

(define (wordlist2para wl)
  (string-join wl " "))

(wordlist2para '("this" "is" "a" "test"))

;; -> "this is a test"

Upvotes: 2

Related Questions