ここには2つの問題があります。 Double
arithmetic is defined with primitive functions.イドリスはa <= b = True -> b <= c = True -> a <= c = True
を証明することさえできません。(これはすべての時間を保持していないので、これはIdrisのせいではありません)a <= b = True
以外の証拠はありません。 ifThenElse
。
このようなブラインドランタイムプルーフを使用すると(… = True
)、Data.So
は非常に役に立ちます。 ifThenElse (a <= x) … …
は指定されたブールチェックを分岐しますが、ブランチのコードはチェックの結果については認識しません。 choose (a <= x)
では、ブランチの結果はLeft prf
とprf : So (a <= x)
またはRight prf
とprf : So (not (a <= x))
となります。
2つの有界2倍を加算した結果が上限より大きい場合、結果はこの上限になるはずです。
import Data.So
data BoundedDouble : (a, b : Double) -> Type where
MkBoundedDouble : (x : Double)
-> {auto high : So (a <= x)}
-> {auto low : So (x <= b)}
-> BoundedDouble a b
Num (BoundedDouble a b) where
(+) (MkBoundedDouble u) (MkBoundedDouble v) =
let x = u + v
in case (choose (a <= x), choose (x <= b)) of
(Left _, Left _) => MkBoundedDouble x
(Right _, _) => ?holeMin
(_, Right _) => ?holeMax
これはすでにタイプチェックされていますが、穴が空いています。 ?holeMin
をMkBoundedDouble a
に、?holeMax
をMkBoundedDouble b
に設定します。しかし、今すぐMkBoundedDouble
の2つの証明:high
とlow
が必要です。 ?holeMax
の場合、それらはx = b
So (a <= b)
とSo (b <= b)
となります。再び、Idrisは、b : Double
ごとにb <= b
を知らない。だから我々は、これらの証明を取得するために再度選択する必要があります:
(_, Right _) => case (choose (a <= b), choose (b <= b)) of
(Left _, Left _) => MkBoundedDouble b
_ => ?what
イドリスはb <= b
は、関数は部分的であろうと見ることはできませんので。私たちは不正行為をして?what
にMkBoundedDouble u
を使用することができるので、関数はタイプチェックを行い、これが実際には起こらないことを望みます。
b <= b
は常に真であることを力で型チェッカーを説得する可能性もあります:
data BoundedDouble : (a, b : Double) -> Type where
MkBoundedDouble : (x : Double)
-> {auto rightSize : So (a <= b)}
-> {auto high : So (a <= x)}
-> {auto low : So (x <= b)}
-> BoundedDouble a b
DoubleEqIsSym : (x : Double) -> So (x <= x)
DoubleEqIsSym x = believe_me (Oh)
Num (BoundedDouble a b) where
(+) (MkBoundedDouble u) (MkBoundedDouble v) =
let x = u + v
in case (choose (a <= x), choose (x <= b)) of
(Left _, Left _) => MkBoundedDouble x
(Right _, _) => MkBoundedDouble a {high=DoubleEqIsSym a}
(_, Right _) => MkBoundedDouble b {low=DoubleEqIsSym b}
それとも私たちも、より安全で、データコンストラクタで上限と下限のための証明を置くことができ、そのため、?holeMin
と?holeMax
に使用できます。
コンストラクタがプルーフでパックされていても、実装が複雑にならないことがわかります。そして、それらは実際の実行時コードで消去されるべきです。
しかし、練習として、あなたはイドリスのために多くのリソースがまだ存在していない、悲しいこと
data BoundedDouble : (a, b : Double) -> Type where
MkBoundedDouble : (x : Double)
-> {auto rightSize : So (a <= b)}
-> {auto high : So (a <= x)}
-> {auto low : So (x <= b)}
-> BoundedDouble a b
Min : {auto rightSize : So (a <= b)} -> BoundedDouble a b
Max : {auto rightSize : So (a <= b)} -> BoundedDouble a b
ためNum
を実装しようとすることができます。チュートリアルの他に、開発中のa bookがあります。私はこれをお勧めします。これは、プリミティブ型で作業するよりも、より親しみやすい演習を提供します。 :-)
ありがとう、あなたの答えは非常に便利です!しかし、もう一度説明してください。どうして私たちは証明書 '' 'So(b <= b)' ''と '' 'So(a <= a)' ''を必要としますか? –