0

Clojure でいくつかの基本的な物理/化学式を実装したいと考えています。性能ではなく利便性を重視したいので、主な機能は型チェックです。メタを数値に付ければ、そのタスクは達成されると考えていました。

たとえば、この関数:

(defn force [mass accel]
  (* mass accel))

したほうがいい

  1. 最初の引数のメタにアクセスする
  2. 質量タイプ、つまりキログラム、グラムなどであることを確認してください。そうでない場合はエラーをスローします。
  3. 数値をキログラムに変換します。
  4. 加速についても同じことを行います。
  5. ニュートンのメタで結果を返します。

*自分の名前空間で適切に他の関数をオーバーロードできます。

唯一の問題は、メタを にアタッチできないことDoubleです。数値のように振る舞うが、メタデータを持つことができる何かを取得する良い方法は何ですか?

4

2 に答える 2

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-kgto-mss関数が型自体をチェックする場合は、 でそれらを省略できますforce。メタデータを含む数字を持つことの便利さを想像して、マップの単純さと透明性をあきらめないでください。

于 2013-10-14T00:28:01.303 に答える
1

を使用したアプローチを次に示しgen-classます。単位をチェックして正規化する関数をモックしただけです。実装されている唯一の操作は*、 で使用される which ですforce

gen-classコードは を使用しているため、次のコードをleiningen プロジェクト フォルダー のフォルダーにあるcompile名前のファイルに保存してからロードする必要があることに注意してください。big_decimal_meta.cljsrc

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)))
于 2013-10-13T14:17:10.983 に答える