Types 依赖类型能否在n-arg函数上抽象?
在动态类型语言中,我可以创建一个函数,该函数将函数作为参数并返回函数 例如,Clojure中的Types 依赖类型能否在n-arg函数上抽象?,types,dynamic-typing,static-typing,dependent-type,Types,Dynamic Typing,Static Typing,Dependent Type,在动态类型语言中,我可以创建一个函数,该函数将函数作为参数并返回函数 例如,Clojure中的memoize函数 (def memoized-fn (memoize any-function)) 在本例中,memoize不关心任何函数所引用的函数,也不关心它接受多少个参数* *实际上,它并不关心传入的内容,(memoize 10)是有效的Clojure,但尝试使用返回值只会引发异常 在以前的生活中,我想用静态类型语言创建类似的东西,在我的例子中,我使用Scala,Scala有许多函数n
memoize
函数
(def memoized-fn
(memoize any-function))
在本例中,memoize
不关心任何函数所引用的函数,也不关心它接受多少个参数*
*实际上,它并不关心传入的内容,(memoize 10)
是有效的Clojure,但尝试使用返回值只会引发异常
在以前的生活中,我想用静态类型语言创建类似的东西,在我的例子中,我使用Scala,Scala有许多
函数n
类型(我相信1 arg到23 arg),但是,如果函数之间没有任何关系,似乎就无法利用它们的函数性来创建单个泛型函数
最后我得到了这样的东西*
def m(fn: Function1[A,Z]) : Function1[A,Z]
def m(fn: Function2[A,B,Z]) : Function2[A,B,Z]
....
def m(fn: Function23[A,B,....,Z]) : (fn: Function23[A,B,....,Z])
(实际上,我在FN4或FN5附近停了下来,因为虽然我很高兴Function23能够存在,但我从来不想实际使用它。)
*这可能也是psuedo-Scala代码,我已经有一段时间没有写过了
回到今天:我了解到,使用依赖类型,我可以创建一个函数,该函数接受一个用值参数化的参数。这方面的一个老生常谈的例子似乎是一个函数,它接受任何类型和大小的列表n,并返回一个大小相同的列表n 我可以理解同质列表(一种大小为n的a类列表),但我还不知道异质列表是否有这种可能性 由此我假设我可以创建一个函数,它接受n个相同类型的参数。大致如下:
def m(fn: Function[n,A]): Function[n,A]
我想我的实际问题是:依赖值能否以异构的方式影响类型的数量 另请注意:请将上述备忘录示例和语言仅作为我想法的示例,我不是问如何使用静态类型语言进行备忘录,而是问一个更高层次的问题,以备忘录代码为例 *请原谅我在这个问题上缺乏更好的词汇,我仍然在学习很多。也欢迎提出编辑/改进建议。依赖类型(PI)基本上是功能空间的“强化”形式(箭头) 如果你看到:
Pi x : T. T(x)
然后它的类型基本上是说“给我一个x类型的T
,我会给你一些T(x)
”
在退化情况下,T
的主体中没有任何x
的实例,这相当于其他语言中的T1->T2
(用T1
替换上面x
中的东西)。对你的问题的简单回答是,不,你通常不能增加一个类型中的“箭头数”,但是你可以做一些基本上是这样的事情,如果你有这个
Pi x : nat. listoflength(x)
其中,listoflength
是生成长度为x
的列表(某种类型,可能是另一个参数)。例如,您可以使用sigma类型来实现它(例如,以长度作为其参数的列表)。问题是参数必须是同质类型。另一种方法是创建一个函数,给定一个参数,该函数将返回一个包含n
事物的元组,每个事物都有某种类型
基本的问题是,如果你给出一个特定的n
,那么你需要能够说,“我接受n
参数,这里是它们的类型”,以使所有类型的算术运算都有效
因此,虽然不能创建任意数量的箭头,但可以创建一些生成一个以元组作为输入的函数的东西(我想如果您知道n
,可以在使用它的地方取消对它的修剪)
在实际的依赖类型编程中,我不知道这会有多大用处(我没有证据表明它没有用处),但我可以看到函数采用特定大小的列表的情况,其中大小必须有一些静态计算来证明它们“匹配”。在要接受异构输入类型的情况下,在实践中对此进行推理可能会很复杂,我通常会在编码实践中尽量避免这种情况。在动态语言中,你可以有不同数量的参数,看起来用例可能是让你在道德上很容易地“重载”一个函数,但是在依赖类型的语言中,似乎您从中获得的任何符号便利都将丢失,因为您必须证明您正确地使用了实例。如果您知道arity-generic数据类型通用编程论文中描述的技巧,那么编写异构arity-generic函数很容易。首先,您创建一个函数,它接收类型的向量,然后,您“curry”这个函数,以便它接收隐式类型而不是显式向量 首先是一些进口产品:
open import Data.Nat
open import Data.Vec
open import Data.Vec.N-ary
本文中有两个组合词:
∀⇒ : ∀ {n α β} {A : Set α}
-> (Vec A n -> Set β)
-> Set (N-ary-level α β n)
∀⇒ {0} B = B []
∀⇒ {suc n} B = ∀ {x} -> ∀⇒ (λ xs -> B (x ∷ xs))
λ⇒ : ∀ {n α β} {A : Set α} {B : Vec A n -> Set β}
-> ((xs : Vec A n) -> B xs)
-> ∀⇒ B
λ⇒ {0} f = f []
λ⇒ {suc n} f = λ {x} -> λ⇒ (λ xs -> f (x ∷ xs))
以及依赖多态性arity泛型组合函数,该函数接收类型的显式向量
Vec-ary : ∀ {α γ l} -> Vec (Set α) l -> Set γ -> Set (N-ary-level α γ l)
Vec-ary [] Z = Z
Vec-ary (X ∷ Xs) Z = X -> Vec-ary Xs Z
compT : ∀ {α β γ l} {Y : Set β}
-> (Xs : Vec (Set α) l)
-> Vec-ary Xs Y
-> (Y -> Set γ)
-> Set (N-ary-level α γ l)
compT [] y Z = Z y
compT (X ∷ Xs) g Z = (x : X) -> compT Xs (g x) Z
comp' : ∀ {α β γ l} {Y : Set β} {Z : Y -> Set γ}
-> (Xs : Vec (Set α) l)
-> (f : (y : Y) -> Z y)
-> (g : Vec-ary Xs Y)
-> compT Xs g Z
comp' [] f y = f y
comp' (X ∷ Xs) f g = λ (x : X) -> comp' Xs f (g x)
现在很容易使类型隐式化:
comp : ∀ {α β γ} {Y : Set β} {Z : Y -> Set γ}
-> (n : ℕ)
-> ∀⇒ (λ (Xs : Vec (Set α) n)
-> (f : (y : Y) -> Z y)
-> (g : Vec-ary Xs Y)
-> compT Xs g Z)
comp n = λ⇒ {n} comp'
和测试:
zeros : (n : ℕ) -> Vec ℕ n
zeros 0 = []
zeros (suc n) = 0 ∷ zeros n
comp-test-func-1 : ℕ -> Vec ℕ 0 -> Vec (Vec ℕ 1) 2 -> ℕ
comp-test-func-1 _ _ _ = 3
test-comp-1 : ℕ -> Vec ℕ 0 -> Vec (Vec ℕ 1) 2 -> Vec ℕ 3
test-comp-1 = comp 3 zeros comp-test-func-1
但是有一个缺点:所有类型必须位于同一个宇宙中,因此此测试无法通过:
comp-test-func-2 : Set -> Vec ℕ 0 -> Vec (Vec ℕ 1) 2 -> ℕ
comp-test-func-2 _ _ _ = 3
test-comp-2 : Set -> Vec ℕ 0 -> Vec (Vec ℕ 1) 2 -> Vec ℕ 3
test-comp-2 = comp 3 zeros comp-test-func-2
因为Set
和Vecℕ 0
位于不同的宇宙中
但是,可以生成一个完全多态的复合函数,但只能使用半显式参数。所以comp3
变成comp(\u∷ _ ∷ _ ∷ [])
,这很难看