2

ハスケルの冒険は続きます。

現在、Haskellで自分のニーズに合った独自のFractionタイプを構築しようとしています。基本的にはFraction{n:: Int、d :: Int}型と多くの関数であり、それらのほとんどはx->Fraction型です。

だから私が今やりたいのは、他の可能性をそれらの1つに変換することによって、分数が分子でのみ正または負、分母で正になることを確認することです。

   --e.g
      (Fraction (3 (-5))->Fraction (-3) 5
   --and
      (Fraction (-3) (-5))->Fraction 3 5

ある関数x->Fractionがそれらの1つを返すたびに。すべてのx->Fraction関数を1つずつ変更するよりも、これを行うためのより賢い方法が必要だと思います。私の推測では、すでに分数タイプの定義にあります。

私はそれほど長い間プログラミングをしていないので、専門用語で完全に打ち負かすことができないかもしれません。

読んでくれてありがとう、そして答えたらありがとう

編集

Eq Instanceソリューションを使用することにし、Signum分子* Signum分母が一致しない場合は、falseをガードに返すことを追加しました。とにかくnumを分割するためにそれを作らなければなりませんでした。とデン。比較する前にHCDと

私が最初に要求したスマートコンストラクターは、同時に作成しているMatrix nXn(Q)モジュールでも使用されます:)

素晴らしい答え。ありがとう。

4

4 に答える 4

8

スマートコンストラクターを使用して、型に対するこれらの制約を確認し、データコンストラクターをエクスポートしないことで非表示にすることができます。スマートコンストラクターは、本質的に、型システムでは強制できない制約を保証する関数です。

于 2012-05-09T12:31:00.097 に答える
5

私は実際に値をそのままにして計算を続けますが、本当に必要な場合は、の定義を別のFractionモジュールに入れ、そのコンストラクターをエクスポートしないでください。makeFraction :: Int -> Int -> Fraction代わりに、 「変換」を処理するのような関数をエクスポートします。

これで、モジュール外の全員が、希望する方法で分数を作成することしかできなくなります。

于 2012-05-09T12:26:20.590 に答える
3

内部表現をそのままにしておくのが一つのアイデアだと思います。つまり、数値を操作するまで、分子と分母の実際の符号は気になりません。

たとえば、Eqクラスのインスタンスを導出することによって行われる2つの分数を比較する場合(もちろん、型クラスについての知識が少し必要です)、次のことを簡単に確認できます。

signum d1 * signum n1 == signum d2 * signum n2

値をチェックすることに加えて。

分数を処理するときにチェックする他の側面もあることに注意してください。例えば:

Fraction 6 2 == Fraction 3 1

別の方法としては、別の符号フィールドを追加し、分子と分母に自然数のようなものを使用する必要があります。

于 2012-05-09T12:31:08.333 に答える
3

Intではなく実際に使用している場合Integer、型システム(および実装)は、トリックや隠蔽なしでこの特定の問題を解決できます。タイプWordは正のマシン整数を表します。

Prelude Data.Word> [minBound,maxBound] :: [Word]
[0,18446744073709551615]
Prelude Data.Word> [minBound,maxBound] :: [Int]
[-9223372036854775808,9223372036854775807]

だからあなたは書くことができます:

import Data.Word

data Fraction = Int :/ Word deriving Show

fi = fromIntegral

instance Eq Fraction where
  (i :/ w) == (j :/ v) = i * fi v == j * fi w

instance Num Fraction where
  fromInteger n = fromInteger n :/ 1
  (i :/ w) * (j :/ v) = (i * j) :/ (w * v)
  (i :/ w) + (j :/ v) = i * fi v + j * fi w :/ w * v 
  (i :/ w) - (j :/ v) =  (i :/ w) + (negate j :/ v)
  negate (i :/ w) = (negate i:/ w)
  abs (i :/ w) = (abs i :/ w)  
  signum (i :/ w) = (signum i :/ 1)

厳密さと開梱により、マシン番号のような動作が得られます。

 data Fraction = {-#UNPACK#-} !Int :/ {-#UNPACK#-} !Word deriving Show
于 2012-05-09T14:20:25.003 に答える