我想在Clojure中实现一些基本的物理/化学公式。 我想强调的不是性能,而是方便,所以主要 功能是类型检查。我在考虑将元数字附加到数字上 将完成任务。
例如,这个函数:
(defn force [mass accel]
(* mass accel))
应该
我可以在命名空间中适当地重载*
和其他函数。
唯一的问题是无法将meta附加到Double
。
获得一个行为类似于数字但可以拥有元数据的好方法是什么?
答案 0 :(得分:2)
如果您只是创建包含数字和单位的地图,而不是尝试将该单位作为数字元数据的一部分进行走私,则所有这一切都要容易得多。毕竟,该单元不是概念上关于数字的簿记数据:它是您正在执行的计算的组成部分。这并不是说你可以在忽略其单位的情况下使用该数字,因此将装饰数字传递给某些“哑”单位不知情函数(例如+
)的能力也不是很有趣。
鉴于这一切,您可以轻松实现force
示例功能:
(defn force [{munit :unit :as mass} {aunit :unit :as accel}]
(assert (mass? munit))
(assert (accel? aunit))
{:unit :newton, :magnitude (* (:magnitude (to-kg mass))
(:magnitude (to-mss accel)))})
当然,如果您的to-kg
和to-mss
函数自行检查类型,则可以在force
中省略它们。不要放弃地图的简单性和透明度,以便在数字上加上元数据的想象方便。
答案 1 :(得分:1)
这是使用gen-class
的方法。我只是嘲笑了检查和规范化单位的功能。实施的唯一操作是*
force
。
请注意,由于代码使用gen-class
和compile
,您需要将以下代码保存到您big_decimal_meta.clj
文件夹中名为src
的文件中leiningen项目文件夹然后加载它。
BigDecimalMeta
使用gen-class
:
(ns big-decimal-meta
(:refer-clojure :exclude [* force])
(:gen-class
:name BigDecimalMeta
:extends java.math.BigDecimal
:state metadata
:init init
:implements [clojure.lang.IObj]))
(defn -init [& args]
[args (atom nil)])
(defn -withMeta [this metadata]
(reset! (.metadata this) metadata)
this)
(defn -meta [this]
(deref (.metadata this)))
(compile 'big-decimal-meta)
*
和force
函数包含一些示例代码:
(def x (with-meta (BigDecimalMeta. 1) {:unit :kg}))
(def y (with-meta (BigDecimalMeta. 3.5) {:unit :mss}))
(def z (with-meta (BigDecimalMeta. 4.5) {:unit :V}))
(defn unit [x]
(-> x meta :unit))
(defn * [x y]
(BigDecimalMeta. (str (.multiply x y))))
(defn mass? [x]
(#{:kg :gr :mg ,,,} (unit x)))
(defn accel? [x]
(#{:mss ,,,} (unit x)))
(defn to-kg [x] x)
(defn to-mss [x] x)
(defn force [mass accel]
(assert (mass? mass))
(assert (accel? accel))
(let [mass (to-kg mass)
accel (to-mss accel)]
(with-meta (* mass accel) {:unit :N})))
(println (force x y) (meta (force x y)))
(println (force x z) (meta (force x z)))