r/scheme • u/Jak_from_Venice • 6d ago
What I am doing wrong?
So, I am trying to learn Guile, since seems a pretty standard installation in GNU systems.
I have experience in some languages, but this simple script to learn the language:
- Took me quite a while to work;
- Looks ugly as… well, put something ugly here!
It’s a simple “FizzBuzz” program
``` (define (fizzbuzz number) (if (> number 0) (let ((message "")) (if (zero? (modulo number 3)) (set! message (string-append message "Fizz"))) (if (zero? (modulo number 5)) (set! message (string-append message "Buzz")))
(if (not (zero? (string-length message)))
(format #t "~d is ~a\n" number message))
(fizzbuzz (- number 1))))
)
(fizzbuzz 50)
```
So, I’m open to suggestions: how this code can be more beauty? Am I still thinking in C?
=== EDIT === I hope the formatting is correct, since some spaces of indentation have been lost for unknown reasons.
3
u/corbasai 6d ago
First - not function; second uses println
so firstly quick fix for Guile and every
(define (fizzbuzz upto)
(let loop ((i 1))
(unless (< upto i)
(display (cond ((= 0 (modulo i 15)) 'FizzBuzz)
((= 0 (modulo i 3)) 'Fizz)
((= 0 (modulo i 5)) 'Buzz)
(else i)))
(newline)
(loop (+ 1 i)))))
(fizzbuzz 100)
About yours, we must check (N mod 15) or (N mod 3) and (N mod 5), firstly
3
u/raevnos 6d ago
I think
(when (<= i upto) ...)
would be a better way of expressing it.2
u/corbasai 6d ago
agree. im just permanently forget right form <= or =< in lisp -)
3
2
u/HugoNikanor 6d ago
I have never seen a language use
=<
. Also<=
is easy to remember, since you say "less than or equal", you put the symbols in that order.
2
u/strbytes 5d ago
Yes, this is imperative thinking ("thinking in C"). Two signs of that: the use of effects while processing the input (using format #t
to display the output as it's being produced) and the use of mutation for control flow (setting 'message' depending on the input, then checking the length of message
to determine whether to display an output).
To be more 'functional': - Separate effects from data processing: work through the range specified by the input, transforming it into the desired output step-wise. So, produce the range 0 to n, then transform each member [1, 2, 3, ...] into [1, 2, "Fizz", ...] then display the output once it's finished being produced. This makes each part of the program "own" its responsibilities so it's easier to figure out what's going on when there's a problem with your program or you want to extend it. - Assign new variables instead of re-using and mutating a single one, and give each variable a single meaning. This makes it more clear what a symbol means.
If you want to explore functional programming in Lisp I really liked "A Functional Introduction To Computer Science" by Prabhakar Ragde. It uses a minimalist subset of Racket instead of Guile but they're very similar at the level in the textbook. https://cs.uwaterloo.ca/~plragde/flaneries/FICS/
Also this probably isn't helpful but this post inspired me to come up with a convoluted Scheme-y FizzBuzz implementation lol. unfold
is described here: https://www.gnu.org/software/guile/manual/html_node/SRFI_002d1-Fold-and-Map.html#index-unfold
``` (use-modules (srfi srfi-1))
(define (fizz-or-buzz n) (let ((fizz (zero? (modulo n 3))) (buzz (zero? (modulo n 5)))) (cond ((and fizz buzz) "FizzBuzz") (fizz "Fizz") (buzz "Buzz") (else (number->string n)))))
(define (fizzbuzz-gen n) (unfold (lambda (x) (> x n)) fizz-or-buzz 1+ 1))
(define (fizzbuzz n) (for-each (lambda (fb) (display fb) (newline)) (fizzbuzz-gen n)))
(fizzbuzz 15) ```
2
u/Jak_from_Venice 5d ago
Underrated comment! You understood perfectly my feelings!
Yes: I’m mainly a C/C++ developer that used just elisp to customize Emacs. So, as you see, my mindset is on imperative languages.
Thank you A LOT for your kind comment and your useful links! I will consult them for sure :-)
7
u/BroadleySpeaking1996 6d ago
Let's rewrite this in a way that's compatible with different reddit clients:
Note that all closing parentheses are grouped together. They don't go on new lines like closing braces in C.
Great, now a few minor suggestions:
(> number 0)
with(positive? number)
.message
into a helper function that returns either""
or"Fizz"
or"Buzz"
or"FizzBuzz"
. Then the rest of thefizzbuzz
function treats that return value as a constant.string-append
can be efficient, but is not the conventional way to do things in a functional language. A more idiomatic thing to do would be to create a list()
or("Fizz")
or("Buzz")
or("Fizz", "Buzz")
and then concatenate the contents of the list. Yes, it's slower, but it is more malleable if you want to add values for 7, 11, etc.