具有标记值的安全API

时间:2019-05-18 19:49:20

标签: ffi agda

许多库都有一个接口,在该接口上,必须首先调用一个函数来初始化该库,该接口将返回一些值(通常是一个指针,有时称为“上下文”或“句柄”)以传递给其他函数,例如(在C):

Library *initialize(long flags);
A mkA(Library *library, long n);
B mkB(Library *library, A a);

如果未使用相同的上下文mkB创建a,则调用library是错误的。

我想在Agda(通过Haskell)中绑定API,并在类型系统中强制执行相同上下文的要求,但不确定如何安全地这样做。 (请注意,API是纯净的,例如,mkA每次使用相同的参数调用时都会返回一个等效值。)我对API的想法如下:

module Data.Tagged where
open import Level
data Tagged {ℓ ℓ′} {A : Set ℓ} (a : A) (B : Set ℓ′) : Set (ℓ ⊔ ℓ′) where
    tag : B → Tagged a B
module Raw where
    postulate
        Library A B HsWord : Set
        initialize : IO Library
        mkA : Library → HsWord → A
        mkB : Library → A → B
    {-# COMPILE GHC Library = type Library #-}
    {-# COMPILE GHC A = type A #-}
    {-# COMPILE GHC B = type B #-}
    {-# COMPILE GHC HsWord = type Word #-}

open import Data.Tagged
open Raw public using (Library)
module _ {lib : Library} where
    A B : Set
    A = Tagged lib A
    B = Tagged lib B
    mkA : Raw.HsWord → A
    mkA n = tag (Raw.mkA lib n)
    mkB : A → B
    mkB a = tag (Raw.mkB lib a)

因此将确保类型安全-mkB仅接受使用相同A进行的Library值-除非可以写以下术语:

castTagged : ∀ {a a′ B} → Tagged a B → Tagged a′ B
castTagged (tag b) = tag b

我会定义

A = Tagged lib A
B = Tagged lib B

抽象,除非它们即使在同一模块中的其他类型签名中也变得不可约。我希望能够将它们定义为在同一模块中可还原,而在其他模块中不可还原,但不确定是否可行。我想将Data.Tagged保留在一个单独的模块中,以便在那里证明其他定理,而不是为我要绑定的每个库重新定义它。

无论如何,如何在Agda中定义这样一种标签安全的API?

0 个答案:

没有答案