如何将 Agda 中的两个自然数与标准库(如 N -> N -> Bool)进行比较?
How to compare two natural numbers in Agda with standard library (like N -> N -> Bool)?
我可以通过手动编写比较器来比较两个自然数:
is-≤ : ℕ → ℕ → Bool
is-≤ zero _ = true
is-≤ (suc _) zero = false
is-≤ (suc x) (suc y) = is-≤ x y
不过,我希望标准库中有类似的东西,所以我不会每次都这样写。
我能够找到 _≤_
运算符 in Data.Nat,但它是一个参数化类型,基本上包含 "proof" 一个特定数字小于另一个(类似于 _≡_
).有没有办法使用它或其他东西来理解哪个数字小于另一个"in runtime"(例如return对应Bool
)?
我要解决的更大问题:
- 作为我作业的一部分,我正在编写一个
readNat : List Char → Maybe (ℕ × List Char)
函数。它尝试从列表的开头读取自然数;稍后将成为 sscanf
. 的一部分
- 我想实现
digit : Char → Maybe ℕ
辅助函数来解析单个十进制数字。
- 为了这样做,我想比较
primCharToNat c
与 primCharToNat '0'
、primCharToNat '1'
并决定是 return None
还是 (primCharToNat c) ∸ (primCharToNat '0')
@gallais 在评论中建议的解决方案:
open import Data.Nat using (ℕ; _≤?_)
open import Data.Bool using (Bool)
open import Relation.Nullary using (Dec)
is-≤ : ℕ → ℕ → Bool
is-≤ a b with a ≤? b
... | Dec.yes _ = Bool.true
... | Dec.no _ = Bool.false
这里我们匹配一个证明 _≤_
是可以使用 with
子句判定的。人们可以在更复杂的功能中类似地使用它。
@user3237465 在对此答案的评论中提出的建议:您还可以使用 shorthand ⌊_⌋
(\clL
/\clR
或 \lfloor
/\rfloor
) 其中 does this exact pattern matching 并消除对 is-≤
:
的需要
open import Data.Nat using (ℕ; _≤?_)
open import Data.Bool using (Bool)
open import Relation.Nullary.Decidable using (⌊_⌋)
is-≤ : ℕ → ℕ → Bool
is-≤ a b = ⌊ a ≤? b ⌋
另一种方法是使用compare
,它也提供了更多信息(例如两个数字之间的差异):
open import Data.Nat using (ℕ; compare)
open import Data.Bool using (Bool)
open import Relation.Nullary using (Dec)
is-≤' : ℕ → ℕ → Bool
is-≤' a b with compare a b
... | Data.Nat.greater _ _ = Bool.false
... | _ = Bool.true
is-≤3' : ℕ → Bool
is-≤3' a with 3 | compare a 3
... | _ | Data.Nat.greater _ _ = Bool.false
... | _ | _ = Bool.true
请注意,由于某种原因,compare
使用常数值 。
我可以通过手动编写比较器来比较两个自然数:
is-≤ : ℕ → ℕ → Bool
is-≤ zero _ = true
is-≤ (suc _) zero = false
is-≤ (suc x) (suc y) = is-≤ x y
不过,我希望标准库中有类似的东西,所以我不会每次都这样写。
我能够找到 _≤_
运算符 in Data.Nat,但它是一个参数化类型,基本上包含 "proof" 一个特定数字小于另一个(类似于 _≡_
).有没有办法使用它或其他东西来理解哪个数字小于另一个"in runtime"(例如return对应Bool
)?
我要解决的更大问题:
- 作为我作业的一部分,我正在编写一个
readNat : List Char → Maybe (ℕ × List Char)
函数。它尝试从列表的开头读取自然数;稍后将成为sscanf
. 的一部分
- 我想实现
digit : Char → Maybe ℕ
辅助函数来解析单个十进制数字。 - 为了这样做,我想比较
primCharToNat c
与primCharToNat '0'
、primCharToNat '1'
并决定是 returnNone
还是(primCharToNat c) ∸ (primCharToNat '0')
@gallais 在评论中建议的解决方案:
open import Data.Nat using (ℕ; _≤?_)
open import Data.Bool using (Bool)
open import Relation.Nullary using (Dec)
is-≤ : ℕ → ℕ → Bool
is-≤ a b with a ≤? b
... | Dec.yes _ = Bool.true
... | Dec.no _ = Bool.false
这里我们匹配一个证明 _≤_
是可以使用 with
子句判定的。人们可以在更复杂的功能中类似地使用它。
@user3237465 在对此答案的评论中提出的建议:您还可以使用 shorthand ⌊_⌋
(\clL
/\clR
或 \lfloor
/\rfloor
) 其中 does this exact pattern matching 并消除对 is-≤
:
open import Data.Nat using (ℕ; _≤?_)
open import Data.Bool using (Bool)
open import Relation.Nullary.Decidable using (⌊_⌋)
is-≤ : ℕ → ℕ → Bool
is-≤ a b = ⌊ a ≤? b ⌋
另一种方法是使用compare
,它也提供了更多信息(例如两个数字之间的差异):
open import Data.Nat using (ℕ; compare)
open import Data.Bool using (Bool)
open import Relation.Nullary using (Dec)
is-≤' : ℕ → ℕ → Bool
is-≤' a b with compare a b
... | Data.Nat.greater _ _ = Bool.false
... | _ = Bool.true
is-≤3' : ℕ → Bool
is-≤3' a with 3 | compare a 3
... | _ | Data.Nat.greater _ _ = Bool.false
... | _ | _ = Bool.true
请注意,由于某种原因,compare
使用常数值