如何在 Common Lisp 中简洁优雅地验证列表的元素

问题描述 投票:0回答:1

我正在尝试验证(在 Common Lisp 中)配置文件的行。我已将它们读入列表列表中,格式为 ((lineno parm value &optional freq start end) (...))。 我希望能够验证配置文件的每一行,识别并显示发现的错误,如果发现任何错误,则以 NIL 结果结束该函数。

我有一个工作函数,但看起来很笨重。我也不知道如何从循环语句中传递 NIL 作为函数的最终结果。

这是我的职责...

(defun validate-config-params (config-params)
  "Validate the parsed config parameters."
  (loop for config-param in config-params
          ; config-param is the entire config form (lineno parm value [freq [start [end]]])
        for param = (cadr config-param)
        for line-number = (car config-param)
        for error-message = ""
        with error-count = 0
        do (unless (or (null param) (and (listp param) (every #'atom param))) 
            (setf error-message (format nil "~A Incorrect format." error-message)))
          (unless (symbolp (first param)) 
            (setf error-message (format nil "~A 1st parm not a symbol." error-message)))
          (unless (or (null (second param)) (numberp (second param))) 
            (setf error-message (format nil "~A 2nd parm not a number." error-message)))
          (unless (or (null (third param)) (symbolp (third param))) 
            (setf error-message (format nil "~A 3rd parm not a symbol." error-message)))
          (unless (or (null (fourth param)) (numberp (fourth param))) 
            (setf error-message (format nil "~A 4th parm not a number." error-message)))
          (unless (or (null (fifth param)) (numberp (fifth param))) 
            (setf error-message (format nil "~A 5th parm not a number." error-message)))
          (cond ((not (STRING= error-message ""))
                  (format T "Line ~A: ~A~%       ~A~%" line-number param error-message)
                  (setf error-message "")
                  (incf error-count)
                  nil)
                (t 'good)))
  (unless (> error-count 0)))

对于配置参数...

(defparameter config-params '((1 NIL) 
 (2 NIL) 
 (3 (PENSION 1000 FORTNIGHTLY))
 (4 (DEEMING-LOW-RATE (/ 0.25 100))) 
 (5 (DEEMING-HIGH-RATE (/ 2.25 100)))
 (6 (DEEMING-LOW-THR 100000)) 
 (7 (INTEREST 7.2 YEARLY))))

...我得到这个结果...

* (validate-config-params config-params)
Line 4: (DEEMING-LOW-RATE (/ 0.25 100))
        Incorrect format. 2nd parm not a number.
Line 5: (DEEMING-HIGH-RATE (/ 2.25 100))
        Incorrect format. 2nd parm not a number.
NIL

...这正是我所期望的,但它看起来很笨重。如果我将第 4 行和第 5 行设置为普通数字(即 0.25 和 2.25),它会正确验证,但仍返回 NIL。

我该如何清理它?

validation configuration common-lisp
1个回答
0
投票

我会返回验证结果(t 或 nil)和错误。然后,您可以独立决定如何处理错误(例如打印错误)。

一个临时的定义可能是这样的:

(defun validate-config-parameters (config-parameters)
  (let ((errors (loop :for (line (param value freq start end)) :in config-parameters
                      :unless (symbolp param)
                        :collect (list line 'param param "not a symbol")
                      :unless (or (null value) (numberp value))
                        :collect (list line 'value value "not a number")
                      :unless (or (null freq) (symbolp freq))
                        :collect (list line 'freq freq "not a symbol")
                      :unless (or (null start) (numberp start))
                        :collect (list line 'start start "not a number")
                      :unless (or (null end) (numberp end))
                        :collect (list line 'end end "not a number"))))
    (values (endp errors)
            errors)))
© www.soinside.com 2019 - 2024. All rights reserved.