你能创建一个以依赖类型语言返回依赖arity函数的函数吗?

时间:2014-08-21 02:15:30

标签: haskell agda dependent-type idris

根据我对依赖类型的了解,我认为它应该是可能的,但我以前从未在一种依赖类型的语言中看到过这样的例子,所以我不确定从哪里开始。

我想要的是形式的功能:

f : [Int] -> (Int -> Bool)
f : [Int] -> (Int -> Int -> Bool)
f : [Int] -> (Int -> Int -> Int -> Bool)

等...

此函数获取n Ints的列表,并返回以Int为参数的arity n的谓词函数。在依赖类型的语言中这种事情是否可行?如何实现这样的事情?

3 个答案:

答案 0 :(得分:21)

创建不同arity的函数时,通常需要一个从值到类型的函数。在这种情况下,我们需要List ℕ(或简称 - 列表的长度)到Set的函数:

Predicate : ℕ → Set
Predicate zero    = Bool
Predicate (suc n) = ℕ → Predicate n

这允许我们为每个数字创建不同的类型:

Predicate 0 = Bool
Predicate 1 = ℕ → Bool
Predicate 2 = ℕ → ℕ → Bool
-- and so on

现在,我们如何使用Predicate来表达f的类型?由于我们是依赖类型的语言,我们可以在类型中自由使用价值级函数。所以length似乎很自然:

f : (l : List ℕ) → Predicate (length l)

现在,您没有指定任何特定的f,但为了示例,我将实施一个。{让我们说我们想检查相应位置的所有数字(即列表的第一个元素的函数的第一个参数,等等)是否相等。

我选择了一个相当简单的函数,因此实现起来非常简单。但请注意,这些类型的函数使用各种技巧,与用于实现类型类的可变函数(在Haskell中)不同。

如果给出一个空列表,我们只需返回true

f []       = true

对于非空列表情况,我们创建一个函数,取一个名为n的参数,然后将其与列表的头部(m)进行比较。如果这些数字不相等,我们将快捷方式f的其余部分,并返回一个忽略所有其他数字的函数,只返回false;如果这些数字相等,我们只需继续列表的其余部分:

f (m ∷ ms) = λ n → case m ≟ n of λ
  { (yes _) → f ms
  ; (no  _) → always-false
  }

辅助函数always-false

always-false : ∀ {n} → Predicate n
always-false {zero}  = false
always-false {suc _} = λ _ → always-false

以下是您的使用方式:

test : Bool
test = f (1 ∷ 2 ∷ 3 ∷ []) 1 2 4  -- false

作为最后的评论:当您没有关于要应用它的参数的任何信息时,这些函数不是很有用。例如,如果您在未知长度的列表上使用f(作为另一个函数的参数),您甚至不能应用"谓词"一个数字。列表很可能是空的,在这种情况下,谓词是Bool,不能应用于任何内容。

答案 1 :(得分:12)

@Vitus已经提出了使用依赖类型的Agda解决方案。在这里,我正在评论Haskell,因为你添加了它的标签。

在Haskell中,我们没有Agda中的依赖类型,因此我们不能在类型中编写length l。然而,我们可以使用自定义列表GADT,它使用Peano naturals公开类型级别列表的长度。

data Z
data S n

data List n a where
   Nil :: List Z a
   Cons :: a -> List n a -> List (S n) a

然后,我们可以使用类型族来计算具有(a -> a -> ... -> Bool)个参数的n类型,其中n是给定的类型级自然。

type family Fun n a
type instance Fun Z     a = Bool
type instance Fun (S n) a = a -> Fun n a

以下是您使用它的方式。以下将列表与提供的“参数列表”进行比较。

equalityTest :: Eq a => List n a -> Fun n a
equalityTest = go True
  where go :: Eq a => Bool -> List n a -> Fun n a
        go b Nil = b
        go b (Cons x xs) = \y -> go (x==y && b) xs

-- *ListGADT> equalityTest (Cons 1 (Cons 2 Nil)) 1 2
-- True
-- *ListGADT> equalityTest (Cons 1 (Cons 2 Nil)) 1 3
-- False

答案 2 :(得分:1)

我记得Stephanie Weirich在Agda的arity-generic编程中有一个paper你可能会发现它有用。它比你要求的更进一步,但介绍部分可能提供了一个很好的解释。