首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我是否正确地将这个C++类转换为Common?

我是否正确地将这个C++类转换为Common?
EN

Code Review用户
提问于 2014-01-27 22:21:36
回答 1查看 552关注 0票数 5

下面是我在文章最下面转换为Lisp的原始C++类。

代码语言:javascript
复制
class TrainingData
{
public:
    TrainingData(const string filename);
    bool isEof(void) { return m_trainingDataFile.eof(); }
    void getTopology(vector<unsigned> &topology);

    // Returns the number of input values read from the file:
    unsigned getNextInputs(vector<double> &inputVals);
    unsigned getTargetOutputs(vector<double> &targetOutputVals);

private:
    ifstream m_trainingDataFile;
};

这是一个来自C++神经网络的类,我正在将它转换为Common。整个400行神经网络是这里

下面是我想出的转换。基于上面链接的神经网络,有人能告诉我如果我用下面的Lisp代码正确地转换了上面的C+类吗?在我开始转换整个400行之前,我宁愿有一点保证。

代码语言:javascript
复制
(defclass training-data ()
  ((training-data-stream :reader training-data-stream
                         :writer |set training data stream (using a funky name)|
                         :initarg :training-data-stream))
  )


;;; initialize-instance :after -- This is your 'constructor' code.

(defmethod initialize-instance :after ((td training-data)
                                       &key
                                       training-data-stream
                                       &allow-other-keys)
  ;; Initialize the slot.

  ;; Note that 'opening' a stream, as it is implied by the C++ class
  ;; definiton and leaking the open stream handle is very impolite.

  (let ((is (etypecase training-data-stream
              ((string pathname) (open training-data-stream :direction :input))
              (stream (if (input-stream-p training-data-stream)
                          training-data-stream
                          (error "Not an input stream.")))))
        )
    (|set training data stream (using a funky name)| is td)
    ))


(defgeneric is-eof (td)
  (:method ((td training-data))
   ;; Are you sure you want this method?
   ))

编辑:关于测试,请让我解释:

由于我只是线性代数的中级,所以我对神经网络有了一点了解。这种向Lisp的转换就是我想出如何理解神经网络的方法。我在Lisp方面做得最好,C很好,C++也很好,所以我尝试通过将C++ nn转换为Lisp来学习神经网络。

我没有足够的信息来测试我在这里或链接上发布的代码的任何特定部分。我仍然在学习std::stringstream,我刚刚了解到按位XOR是什么。我可以发布说明,说明如何在链接上完整地运行C++ nn,以及为其创建数据文件的代码,这样您就可以看到它是如何运行的,或者解释我发布的不完整代码片段是如何与其余代码关联的。我在这篇文章中添加的不完整的成员函数已经在我刚才添加的链接中完成了其余代码中的对应项。

EN

回答 1

Code Review用户

发布于 2014-04-15 13:39:32

代码审查--主要是样式

您做了一个从C++到CL的小翻译,这似乎很好。我对它有一些文体上的问题:

代码语言:javascript
复制
(defclass training-data ()
  ((training-data-stream :reader training-data-stream
                         :writer |set training data stream (using a funky    name)|
                         :initarg :training-data-stream)))
  1. 我想|set training data stream (using a funky name)|是一种混淆作者方法的尝试,这样您就可以拥有一种“私有”设置器。别干那事。
    1. :writer是可选的:如果不指定它,就不会为您的插槽生成特定的设置器。您可以始终使用slot-value来更改插槽。然而,我不推荐这种批准。
    2. 您可以定义一个:accessor方法,它同时充当读取器和写入器方法(resp )。(my-accessor instance)(setf (my-accessor instance) value))。由于您的C++字段是private并且没有公共getter/setter,所以这是一种合适的方法:
      • 只定义访问器,比如training-data-stream,和
      • 不要从包中导出training-data-stream符号。在CL中,可见性在包级别进行处理。

  2. 您的initarg可以缩短:在创建training-data类的实例时使用它,因此:training-data-stream是多余的,只需使用:input-stream (:stream太模糊)。

然后..。

代码语言:javascript
复制
;;; initialize-instance :after -- This is your 'constructor' code.

(defmethod initialize-instance :after ((td training-data)
                                       &key
                                       training-data-stream
                                       &allow-other-keys)
  ;; Initialize the slot.

到目前为止,还不错;只需将training-data-stream重命名为input-stream即可。

代码语言:javascript
复制
  ;; Note that 'opening' a stream, as it is implied by the C++ class
  ;; definiton and leaking the open stream handle is very impolite.

你自己的评论强调

  • 原始的C++类可能不擅长遵循C++最佳实践(例如,RAII),以及
  • 您是在逐字复制C++类,而不是使用更加惯用的CL方法。由于您只是复制一个现有的代码基,以了解它,它并不是那么糟糕。也许你以后可以试着重构它,作为一个练习。

此外,“不礼貌”一词不是我会使用的,因为它是不准确的(听起来--如果你忽略了资源泄漏背后的真正问题,或者说它是次要的)。

此后,您的let绑定是无用的:

代码语言:javascript
复制
  (let ((is (etypecase training-data-stream
              ((string pathname) (open training-data-stream :direction :input))
              (stream (if (input-stream-p training-data-stream)
                          training-data-stream
                          (error "Not an input stream.")))))
        )
    (|set training data stream (using a funky name)| is td)
    ))

换句话说,(let ((x (something))) (use x))可以简单地称为(use (something))。此外,通过允许使用流初始化构造函数,而不仅仅是字符串(是否有必要),您更改了最初的行为。

请注意,与好的etypecase不同,您还可以让initialize-instance调用一个新的泛型方法,比如initialize,该方法会对流的类型进行调度,不管是string还是stream (我们不能对&key参数进行分派,否则initialize-instance就足够了)。

代码语言:javascript
复制
    (setf (training-data-stream td)
          (etypecase input-stream
            ((string pathname) (open input-stream :direction :input))
            (stream (if (input-stream-p training-data-stream)
                        training-data-stream
                        (error "Not an input stream."))))))

你的目标

我试图通过将C++ nn转换为Lisp来学习神经网络

在我看来,学习像神经网络这样的高级概念,用一个像你链接的实现是不太有效的。

即使您对C++有困难,但这并不是妨碍您理解神经网络的语言;例如:

代码语言:javascript
复制
    Layer &outputLayer = m_layers.back();
    m_error = 0.0;

    for (unsigned n = 0; n < outputLayer.size() - 1; ++n) {
        double delta = targetVals[n] - outputLayer[n].getOutputVal();
        m_error += delta * delta;
    }
    m_error /= outputLayer.size() - 1; // get average error squared
    m_error = sqrt(m_error); // RMS

这些只是数学运算,它们是用C++编写的,这并不是它们难以掌握的原因。事实上,我从来没有真正研究过神经网络,尽管我熟悉这种语言,但上面的代码都很神秘。

我怀疑用CL重写它对你有帮助。

你首先需要的是一本高层次概念的书籍和教程。尝试使用一个易于使用的库,比如PyBrain,它有一个很好的文档.

也许,当您对神经网络有了很好的理解后,您可以回到链接代码,检查实现,看看它是如何设计的,以及为什么。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/40212

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档