Reputation: 782
I found a short introduction to Scheme online, and I'm having a bit of trouble with this function:
(define (title-style str)
(let loop ((lc #\space) (i 0) (c (string-ref str 0)))
((if (char=? lc #\space)
(string-set! str i (char-upcase c)))
(if (= (- (string-length str) 1) i)
str
(loop c (+ i 1) (string-ref str (+ i 1)))))))
(display "star wars iv: a new hope")
(display (title-style "star wars iv: a new hope"))
When I try calling it, I get this:
Error: call of non-procedure: #<unspecified>
Call history:
title-style.scm:6: loop
...
title-style.scm:1: g6 <--
That error comes from Chicken Scheme, I am also getting the same results in Chez Scheme.
It converts a string to title case, and from the error messages I got earlier, it does: call of non-procedure: "Star Wars Iv: A New Hope"
Upvotes: 2
Views: 1277
Reputation: 236114
I understand what you intend to do, but that's not the right way to structure a conditional expression in Scheme. Also, right before the first if
there's a misplaced opening parentheses (which is the one causing the reported error), and you have to advance the recursion in all cases. This should work for non-empty strings:
(define (title-style str)
(let loop ((lc #\space) (i 0) (c (string-ref str 0)))
(cond ((= (- (string-length str) 1) i)
str)
((char=? lc #\space)
(string-set! str i (char-upcase c))
(loop c (+ i 1) (string-ref str (+ i 1))))
(else
(loop c (+ i 1) (string-ref str (+ i 1)))))))
But still, it's not the recommended way to write a solution in Scheme, you're mutating the input string along the way, which is discouraged, and you're thinking in terms of indexes. Besides, you're imposing an extra restriction on your input: that the strings must be mutable, and not all Scheme dialects support this by default.
A functional tail-recursive style is preferred, where we create a new string as output, leaving the original input untouched and leveraging the rich library of list procedures available in the language; this is what I mean:
(define (title-style str)
(let loop ((lc #\space) (lst (string->list str)) (acc '()))
(cond ((null? lst)
(list->string (reverse acc)))
((char=? lc #\space)
(loop (car lst) (cdr lst) (cons (char-upcase (car lst)) acc)))
(else
(loop (car lst) (cdr lst) (cons (car lst) acc))))))
Either way, it works as expected:
(title-style "star wars iv: a new hope")
=> "Star Wars Iv: A New Hope"
Upvotes: 3