Functional programming 那么:什么';重点是什么?

Functional programming 那么:什么';重点是什么?,functional-programming,agda,dependent-type,idris,Functional Programming,Agda,Dependent Type,Idris,该类型的预期用途是什么?译成Agda: data So : Bool → Set where oh : So true So将布尔命题提升为逻辑命题。Oury和Swierstra的介绍性论文给出了一个由表列索引的关系代数示例。获取两个表的乘积需要它们具有不同的列,因此它们使用So: Schema = List (String × U) -- U is the universe of SQL types -- false iff the schemas share any column

该类型的预期用途是什么?译成Agda:

data So : Bool → Set where
  oh : So true
So
将布尔命题提升为逻辑命题。Oury和Swierstra的介绍性论文给出了一个由表列索引的关系代数示例。获取两个表的乘积需要它们具有不同的列,因此它们使用
So

Schema = List (String × U)  -- U is the universe of SQL types

-- false iff the schemas share any column names
disjoint : Schema -> Schema -> Bool
disjoint = ...

data RA : Schema → Set where
  -- ...
  Product : ∀ {s s'} → {So (disjoint s s')} → RA s → RA s' → RA (append s s')
我习惯于为我想证明的关于我的程序的事情构建证据术语。在
Schema
s上构造逻辑关系以确保不相交似乎更为自然:

Disjoint : Rel Schema _
Disjoint s s' = All (λ x -> x ∉ cols s) (cols s')
  where cols = map proj₁
So
与“适当的”证明术语相比似乎有严重的缺点:
oh
上的模式匹配不会为您提供任何可以进行另一个术语类型检查的信息(是吗?)-这意味着
So
值不能有效地参与交互式证明。这与
不相交的
的计算有用性形成对比,后者表示为证明
s'
中的每列不出现在
s
中的列表

我真的不相信规范
So(不相交的s')
Disjoint s'
更易于编写-您必须在没有类型检查器帮助的情况下定义布尔
Disjoint
函数-并且在任何情况下
Disjoint
在您想要操纵其中包含的证据时会自行付费

我还怀疑
So
在构建
产品
时是否省力。为了给出
So(不相交的s')
,您仍然需要对
s
s'
进行足够的模式匹配,以使类型检查器确信它们实际上是不相交的。丢弃由此产生的证据似乎是浪费


因此
对于部署它的代码的作者和用户来说似乎都不太方便。”那么,在什么情况下我想使用
So

如果你已经有了
b:Bool
,你可以把它变成命题:
sob
,比
b短一点≡ 正确
。有时(我不记得任何实际情况)不需要麻烦使用正确的数据类型,这种快速解决方案就足够了

因此
与“适当”相比似乎有严重的缺点 证明条件:在
oh
上进行模式匹配不会提供任何信息 您可以使用它进行另一个术语类型检查。作为推论,
因此
值不能有效地参与交互式验证。 这与不相交的的计算有用性形成对比,后者 表示为证明
s'
中的每一列不存在的证明列表 出现在
s

因此
确实提供了与不相交的相同的信息-您只需要提取它。基本上,如果
disjoint
disjoint
之间没有不一致,那么您应该能够使用模式匹配、递归和不可能的情况消除来编写函数
So(disjoint s)->disjoint s

但是,如果稍微调整一下定义:

So : Bool -> Set
So true  = ⊤
So false = ⊥
So
成为一种非常有用的数据类型,因为
x:So-true
由于
eta规则,立即减少为
tt
。这样就可以像约束一样使用
:在pseudo Haskell中,我们可以编写

forall n. (n <=? 3) => Vec A n
我使用了这个技巧来回答(它是
{{uu:False(m≟ 0)}
在那里)。我想如果没有这个简单的定义,就不可能写出所描述的机器的可用版本:

Is-just : ∀ {α} {A : Set α} -> Maybe A -> Set
Is-just = T ∘ isJust
其中
T
是Agda标准库中的
So

此外,在存在实例参数时,
So
-as-a-data-type可以用作
So
-as-a-constraint:

open import Data.Bool.Base
open import Data.Nat.Base
open import Data.Vec

data So : Bool -> Set where
  oh : So true

instance
  oh-instance : So true
  oh-instance = oh

_<=_ : ℕ -> ℕ -> Bool
0     <= m     = true
suc n <= 0     = false
suc n <= suc m = n <= m

vec : ∀ {n} {{_ : So (n <= 3)}} -> Vec ℕ n
vec = replicate 0

ok : Vec ℕ 2
ok = vec

fail : Vec ℕ 4
fail = vec
打开导入数据.Bool.Base
打开导入Data.Nat.Base
打开导入数据.Vec
数据So:Bool->设置位置
哦:真的
实例
哦,这是真的
哦实例=哦
_ ℕ -> 布尔

而且,“So b”的每一个证明在命题上都等于任何其他证明,这对于b编码的任何属性的实际“证据”来说都不一定是如此。“有时候你会想要的。”赛赞,说得对。我的答案中的第二个链接也利用了这个属性。你有什么好的用例吗?我觉得这里有一些更深层次的东西,关于用
数据
归纳定义的类型和那些在函数中递归定义的类型之间的关系。你能详细解释一下为什么Agda乐于根据你的定义推断出一个
So
值,而不是我的吗?@Benjamin Hodgson,这是关于
数据
s和
记录
s之间的区别:后者有ETA,而前者没有。
定义上等于
tt
eq:∀ {x} ->x≡ tt;eq=refl
,因此当Agda遇到
\u x时:⊤
,其中
\ux
是元变量,
\ux
被实例化为
tt
,统一问题得到解决。但是,当Agda遇到
\ux:So true
时,她无法将
\ux
与某些东西统一起来,因为这种机制不适用于
数据。但是您可以使用实例参数强制统一,如上所述。@user3237465我在这里使用了类似的东西,所以这个属性。Inj的相等对应于逐点相等。
open import Data.Bool.Base
open import Data.Nat.Base
open import Data.Vec

data So : Bool -> Set where
  oh : So true

instance
  oh-instance : So true
  oh-instance = oh

_<=_ : ℕ -> ℕ -> Bool
0     <= m     = true
suc n <= 0     = false
suc n <= suc m = n <= m

vec : ∀ {n} {{_ : So (n <= 3)}} -> Vec ℕ n
vec = replicate 0

ok : Vec ℕ 2
ok = vec

fail : Vec ℕ 4
fail = vec