【问题标题】:Nullable Double Type-Hint可空的双重类型提示
【发布时间】:2016-11-01 04:26:43
【问题描述】:

我正在编写一个神经网络,并且有以下节点的定义:

(defrecord Node [^double input-sum ^double last-output])

input-sum 是其输入的运行总和;预激活。 last-output 是激活值吗。

我最初的想法是创建一个像(->Node 0 nil) 这样的初始节点。我的理由是在last-output 被激活之前给它一个真正的价值是没有任何意义的。

不幸的是,创建上述节点会产生 NPE;显然是因为它试图将 nil 转换为双精度:

(->Node 0 nil)
NullPointerException   clojure.lang.RT.doubleCast (RT.java:1298)

如果我删除 last-output 上的类型提示,它可以正常工作。

我正在努力养成在我能做的情况下输入提示的习惯。有没有办法在last-output 上提供类型提示,但也表明nil 是一个可接受的值?

【问题讨论】:

  • 您能否更详细地解释一下您为什么“试图养成类型提示的习惯”?这样做是一种过早的优化,我相信你已经听过很多次了,它是万恶之源。
  • @SamEstep 我认为从一开始就定义类型而不是继续下去会更容易
  • 但你不知道你是否真的需要在路上做。正如reference documentation 所述,类型提示纯粹是针对“性能关键代码区域”的性能优化,因此您所做的是过早优化的教科书示例。我强烈建议您阅读these three questions 的答案(如果您还没有的话)。
  • @SamEstep 好的,谢谢。也许我会启用反射警告并处理它,然后查看提到的包以获取文档。
  • 在你已经写好你的代码,对它进行基准测试,发现反射是一个瓶颈之后,添加类型提示并没有什么问题。问题是当您在知道需要它们之前就使用它们来妨碍您的设计。至于文档,我个人推荐clojure.spec;它在标准库中,因此它将成为未来最受支持的选项,并且它具有非常可靠的设计和许多非常棒的功能。

标签: clojure nullable type-hinting


【解决方案1】:

^double 是 Java 原始双精度类型的类型提示。试试^Double

【讨论】:

  • 这是我最初的想法,但拳击可能会变得不可接受。
【解决方案2】:

如果您确实需要使用原始类型进行类型提示,并且不能选择使用对象类型Double(例如出于性能相关原因),则通常的做法(据我所知)是创建自己的自定义构造函数功能:

user> (defrecord Node [^double input-sum ^double last-output])
user.Node

user> (defn make-node [^Double input-sum ^Double last-output]
        (->Node (or input-sum 0) (or last-output 0)))
#'user/make-node

user> (make-node nil 0)
#user.Node{:input-sum 0.0, :last-output 0.0}

user> (make-node 10 nil)
#user.Node{:input-sum 10.0, :last-output 0.0}

user> (make-node 1 2)
#user.Node{:input-sum 1.0, :last-output 2.0}

该方法适用于所有需要复杂逻辑来构建实体的情况。

更新

如果你真的需要both一个原始值以及区分值和“无值”的方法,你可以使用NaN

user> (defn make-node [^Double input-sum ^Double last-output]
        (->Node (or input-sum Double/NaN) (or last-output Double/NaN)))
#'user/make-node

user> (make-node 1 nil)
#user.Node{:input-sum 1.0, :last-output NaN}

所以,它是价值,也是nil的原始类似物。

【讨论】:

  • 但这不是他要问的......将nil 转换为0.0 与“表明[ing] nil 是可接受的值”不同。跨度>
  • 对,不是。但是,如果您有原始类型提示,如果您不想在每次使用 ->Node 时检查所有参数,这是您唯一的选择。
  • 不过,他在问题的任何地方都没有说“原始”。此外,他的声明“在last-output 被激活之前给它一个实际值没有任何意义”似乎暗示他真的想要一个实际的nil 值,而不是0.0(这是,从数学上讲,是“真实的”)。
  • 但是使用类型提示来“指示”某些东西(如果你的意思是“记录”)看起来真的很奇怪。还有其他用于类型注释的工具,如schemaspeccore.typed
  • 好的,很酷。对我来说有点 C 的味道,但在性能确实需要原语的情况下,它可以工作。 :)
猜你喜欢
  • 2020-12-19
  • 2016-08-30
  • 2017-01-18
  • 2017-04-29
  • 2016-01-27
  • 1970-01-01
  • 2012-09-04
  • 2021-05-10
相关资源
最近更新 更多