Case Statement Not Assigning Value

2019-08-04 02:46发布

问题:

I'm having some trouble debugging a case statement. I was hoping that the statement would assign numeric values to note-val, but so far it is assigning #<void>. I know it's something wrong with the case statement, because if I add an else clause, that value gets applied. Given a sample input of '(((#\3 #\A) (#\4 #\B)) ((#\4 #\C))), what am I doing wrong here? (In regards to the case statement. I'm sure there are other errors, but I'd like to try to work those out myself if I can get this fixed.)

(define (calc-freqs chord)
  (let ((octave (char->int (caaar chord)))
        (note-val (case (cdaar chord)
                    [((#\B #\#) (#\C))      0]
                    [((#\C #\#) (#\D #\b))  1]
                    [((#\D))                2]
                    [((#\D #\#) (#\E #\b))  3]
                    [((#\E) (#\F #\b))      4]
                    [((#\E #\#) (#\F))      5]
                    [((#\F #\#) (#\G #\b))  6]
                    [((#\G))                7]
                    [((#\G #\#) (#\A #\b))  8]
                    [((#\A))                9]
                    [((#\A #\#) (#\B #\b)) 10]
                    [((#\B) (#\C #\b))     11])))
    (cons (* a4 (expt 2 (+ (- octave 4) (/ (- note-val 9) 12))))
          (if (pair? (cdr chord))
              (calc-freqs (cdr chord))
              '()))))

Oh, and char->int is a tiny utility function I wrote that pretty much does what it says in the name (#\1 => 1, and so on).

回答1:

case does matching using eqv?. That means that anything other than symbols, numbers, characters, booleans, or the empty list will never match.

In your case, you were trying to match (non-empty) lists. That will never work. :-( (Neither will matching strings or vectors work.)



回答2:

To add to the prior answer (in a way that allows me to add code): if you're using Racket, you might be interested in the "match" form:

#lang racket

(require rackunit)

(define (pitchclass->half-steps pitchclass)
  (match pitchclass
    [(or "B#" "C")   0]
    [(or "C#" "Db")  1]
    ["D"             2]
    [(or "D#" "Eb")  3]
    [(or "E" "Fb")   4]
    [(or "E#" "F")   5]
    [(or "F#" "Gb")  6]
    ["G"             7]
    [(or "G#" "Ab")  8]
    ["A"             9]
    [(or "A#" "Bb") 10]
    [(or "B" "Cb")  11]))

;; TEST CASES:

(check-equal? (pitchclass->half-steps "Ab") 8)
(check-equal? (pitchclass->half-steps (apply string '(#\D #\#))) 3)

The second test case illustrates how you might use this if you're really married to the "list-of-chars" representation.