I have an imperative programming background and I've decided to study functional programming by applying it to problems found on sites such as Project Euler and Rosalind. My language of choice is Scheme (I use CHICKEN). As can be seen, I'm only starting out.
This is about the 3rd problem found on Rosalind, that goes like this:
In DNA strings, symbols 'A' and 'T' are complements of each other, as are 'C' and 'G'.
The reverse complement of a DNA string s is the string sc formed by reversing the symbols of s, then taking the complement of each symbol (e.g., the reverse complement of "GTCA" is "TGAC").
Given: A DNA string s of length at most 1000 bp.
Return: The reverse complement sc of s.
Here's my code, which solves the problem:
(define (complement-of char)
(cond
((eq? char #\A)
#\T)
((eq? char #\T)
#\A)
((eq? char #\C)
#\G)
((eq? char #\G)
#\C)
(else
char)))
(define (apply-complements dna-string)
(reverse-list->string
(map complement-of
(string->list dna-string))))
(define (solve-problem infile-name outfile-name)
(let ((outfile-port (open-output-file outfile-name))
(infile-port (open-input-file infile-name)))
(begin
(write-line
(apply-complements (read-line infile-port)) outfile-port)
(close-output-port outfile-port))))
Is there a nicer way to write complement-of
? Perhaps something like a dictionary, or would that be too much work in this particular case?
Is solve-problem
there appropriate from a style POV, or is this more appropriate?
(define (solve-problem infile-name outfile-name)
(let ((outfile-port (open-output-file outfile-name))
(infile-port (open-input-file infile-name)))
(begin
(write-line
(apply-complements
(read-line infile-port))
outfile-port)
(close-output-port outfile-port))))
Also, is there a way to avoid using begin
and still make things look readable? The only idea that comes to mind is extracting a function and through recursion decide whether or not it writes to the file, or closes it. But that feels hardly intuitive.
Finally, I'd like to hear of any other issues my code has.