我是伊德里斯的新手。我需要创建一个描述有界数字的数据。所以我用这样的构造函数制作了这样的数据:
data BoundedDouble : (a, b : Double) -> Type where
MkBoundedDouble : (x : Double) ->
{auto p : a <= x && x <= b = True} ->
BoundedDouble a b
似乎在Double
和a
之间创建b
。
这是一个简单的使用示例:
test : BoundedDouble 0.0 1.0
test = MkBoundedDouble 0.0
有效。但现在我想为Num
实现BoundedDouble
接口。我试过这个:
Num (BoundedDouble a b) where
(MkBoundedDouble x) + (MkBoundedDouble y) =
MkBoundedDouble (ifThenElse (x + y > b)
(x + y - (b - a))
(ifThenElse (x + y < a)
(x + y + (b - a))
(x + y)))
但它不起作用,我想为什么,但我无法解释。 我该如何实施添加?
我不确切地知道应该做什么或阅读以理解它。
答案 0 :(得分:3)
这里有两个问题。 Double
arithmetic is defined with primitive functions.伊德里斯甚至无法证明a <= b = True -> b <= c = True -> a <= c = True
(顺便说一下,它甚至都没有 - 所以这不是伊德里斯的错。)没有{{1}的证据。其他然后只是检查它,你尝试了a <= b = True
。
使用此类盲运行时证明(仅ifThenElse
)时,Data.So
非常有用。给定布尔检查… = True
分支,但分支中的代码不知道检查结果。使用ifThenElse (a <= x) … …
,您可以获得分支的结果,choose (a <= x)
和Left prf
或prf : So (a <= x)
和Right prf
。
我想如果添加两个有界双精度的结果会比上界更大,结果应该是这个上限。让我们先尝试一下:
prf : So (not (a <= x))
这已经有了类型,但它有漏洞。我们希望将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
和high
。对于low
,?holeMax
x = b
和So (a <= b)
会有So (b <= b)
。同样,Idris不知道每b <= b
b : Double
。所以我们需要再次选择获得这些证据:
(_, Right _) => case (choose (a <= b), choose (b <= b)) of
(Left _, Left _) => MkBoundedDouble b
_ => ?what
因为Idris看不到b <= b
,所以该功能将是部分的。我们可以在MkBoundedDouble u
中欺骗和使用例如?what
,因此该函数将进行类型检查并希望确实不会发生这种情况。
还有可能用力量说服类型检查器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
中使用它们。这将是:
import Data.So
data BoundedDouble : (a, b : Double) -> Type where
MkBoundedDouble : (x : Double)
-> {auto rightSize : So (a <= b)}
-> {auto leftId : So (a <= a)}
-> {auto rightId : So (b <= b)}
-> {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 _, _) => MkBoundedDouble a
(_, Right _) => MkBoundedDouble b
你看,即使构造函数包含证明,它们也不会使实现复杂化。它们应该在实际的运行时代码中被删除。
但是,作为练习,您可以尝试为{/ p>实施Num
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
可悲的是,伊德里斯的资源还不多。除了教程之外,还有a book正在开发中,我建议。它提供了比使用原始类型更平易近人的练习。 : - )