1

假设我有三个对矩阵进行操作的函数:

(defn flip [matrix] (...))
(defn rotate [matrix] (...))
(defn inc-all [matrix] (...))

想象一下,每个函数都需要一个整数向量向量(其中每个内部向量的长度相同)才能正常运行。

我可以提供一个断言矩阵函数来验证矩阵数据的格式是否正确:

(defn assert-matrix [matrix] (...) )

但是,翻转函数(例如)无法知道传递给函数的数据是否已经过验证(完全取决于用户是否会在将数据传递给函数之前对其进行验证)。因此,为了保证正确性,翻转需要定义为:

(defn flip [matrix]
    (assert-matrix matrix)
    (...))

这里有两个主要问题:

  • 每次调用矩阵函数时都必须继续调用 assert-matrix 是低效的。
  • 每当我创建一个矩阵函数时,我必须记住调用 assert-matrix。我很可能会忘记,因为重复这一点很乏味。

在面向对象的语言中,我将创建一个名为 Matrix 的类,它带有一个构造函数,该构造函数在创建实例时检查构造函数 args 的有效性。无需重新检查有效性的方法,因为它们可以确信在初始化类时数据已经过验证。

这将如何在 Clojure 中实现?

4

2 回答 2

2

There are several ways to validate a data structure only once, you could for instance write a with-matrix macro along the lines of the following:

(defmacro -m> [matrix & forms]
  `(do
    (assert-matrix ~matrix
      (-> ~matrix
        ~@forms))

which would allow you to do:

(-m> matrix flip rotate)

The above extends the threading macro to better cope with your use case.

There can be infinite variations of the same approach, but the idea should still be the same: the macro will make sure that a piece of code is executed only if the validation succeeds, with functions operating on matrices without any embedded validation code. Instead of once per method execution, the validation will be executed once per code block.

Another way could be to make sure all the code paths to matrix functions have a validation boundary somewhere.

You may also want to check out trammel.

于 2013-02-04T13:25:24.983 回答
2

您可以使用协议来表示矩阵上的所有操作,然后创建一个类似于矩阵的“构造函数”的函数:

(defprotocol IMatrix                                                                                                                                 
  (m-flip [_])                                                                                                                                       
  (m-rotate [_])                                                                                                                                     
  (m-vals [_]))                                                                                                                                      

(defn create-matrix [& rows]                                                                                                                         
  (if (apply distinct? (map count rows))                                                                                                             
    (throw (Exception. "Voila, what are you doing man"))                                                                                             
    (reify                                                                                                                                           
      IMatrix                                                                                                                                        
      (m-flip [_] (create-matrix rows))                                                                                                              
      (m-rotate [_] (create-matrix rows))                                                                                                            
      (m-vals [_] (vec rows))))) 



(def m (create-matrix [1 2 3] [4 5 6]))                                                                                                              
(m-flip m)
于 2013-02-04T16:03:55.603 回答