如何系统地计算给定类型的居民数量?

时间:2015-10-18 12:58:39

标签: algorithm type-theory system-f

如何系统地计算系统F中给定类型的居民数量?

假设有以下限制:

  • 所有居民终止,即没有底部。
  • 所有居民都缺乏副作用。

例如(使用Haskell语法):

  • Bool有两个居民。
  • (Bool, Bool)有四个居民。
  • Bool -> (Bool, Bool)有十六个居民。
  • forall a. a -> a有一个居民。
  • forall a. (a, a) -> (a, a)有四个居民。
  • forall a b. a -> b -> a有一个居民。
  • forall a. a没有居民。

为前三个算法实现算法是微不足道的,但我无法弄清楚如何为其他算法做到这一点。

1 个答案:

答案 0 :(得分:6)

我想解决同样的问题。以下讨论对我帮助很大:

Abusing the algebra of algebraic data types - why does this work?

起初,我也被forall a. a -> a等类型所困扰。然后,我有一个顿悟。我意识到forall a. a -> a类型是Mogensen-Scott encodingunit type。因此,它只有一个居民。同样,forall a. abottom type的Mogensen-Scott编码。因此,它没有居民。请考虑以下代数数据类型:

data Bottom                         -- forall a. a

data Unit = Unit                    -- forall a. a -> a

data Bool = False | True            -- forall a. a -> a -> a

data Nat = Succ Nat | Zero          -- forall a. (a -> a) -> a -> a

data List a = Cons a (List a) | Nil -- forall a b. (a -> b -> b) -> b -> b

代数数据类型是sumproducts。我将使用语法⟦τ⟧来表示τ类型的居民数量。我将在本文中使用两种类型:

  1. 系统F数据类型,由以下BNF给出:

    τ = α
      | τ -> τ
      | ∀ α. τ
    
  2. 代数数据类型,由以下BNF给出:

    τ = 
      | α
      | τ + τ
      | τ * τ
      | μ α. τ
    
  3. 计算代数数据类型的居民数量非常简单:

    ⟦⟧       = 
    ⟦τ¹ + τ²⟧ = ⟦τ¹⟧ + ⟦τ²⟧
    ⟦τ¹ * τ²⟧ = ⟦τ¹⟧ * ⟦τ²⟧
    ⟦μ α. τ⟧  = ⟦τ [μ α. τ / α]⟧
    

    例如,考虑列表数据类型μ β. α * β + 1

    ⟦μ β. α * β + 1⟧ = ⟦(α * β + 1) [μ β. α * β + 1 / β]⟧
                     = ⟦α * (μ β. α * β + 1) + 1⟧
                     = ⟦α * (μ β. α * β + 1)⟧ + ⟦1⟧
                     = ⟦α⟧ * ⟦μ β. α * β + 1⟧ + ⟦1⟧
                     = ⟦α⟧ * ⟦μ β. α * β + 1⟧ +  1
    

    但是,计算System F数据类型的居民数量并不是那么简单。不过,它可以做到。为此,我们需要将System F数据类型转换为等效的代数数据类型。例如,System F数据类型∀ α. ∀ β. (α -> β -> β) -> β -> β等同于代数列表数据类型μ β. α * β + 1

    首先要注意的是,尽管系统F类型∀ α. ∀ β. (α -> β -> β) -> β -> β有两个通用量词,但代数列表数据类型μ β. α * β + 1只有一个(定点)量词(即代数列表数据类型)是单形的。

    虽然我们可以使代数列表数据类型具有多态性(即∀ α. μ β. α * β + 1)并添加规则⟦∀ α. τ⟧ = ∀ α. ⟦τ⟧但我们不这样做,因为它不必要地使问题复杂化。我们假设多态类型已经专门用于某种单形类型。

    因此,第一步是删除所有通用量词,除了代表"固定点"量词。例如,类型∀ α. ∀ β. α -> β -> α变为∀ α. α -> β -> α

    由于Mogensen-Scott编码,大多数转换都很简单。例如:

    ∀ α. α                       = μ α. 0                   -- bottom type
    
    ∀ α. α -> α                  = μ α. 1 + 0               -- unit type
    
    ∀ α. α -> α -> α             = μ α. 1 + 1 + 0           -- boolean type
    
    ∀ α. (α -> α) -> α -> α      = μ α. (α * 1) + 1 + 0     -- natural number type
    
    ∀ β. (α -> β -> β) -> β -> β = μ β. (α * β * 1) + 1 + 0 -- list type
    

    但是,有些转换不是那么简单。例如,∀ α. α -> β -> α不代表有效的Mogensen-Scott编码数据类型。不过,我们可以通过稍微处理这些类型得到正确的答案:

    ⟦∀ α. α -> β -> α⟧ = ⟦β -> ∀ α. α -> α⟧
                       = ⟦∀ α. α -> α⟧ ^ ⟦β⟧ 
                       = ⟦μ α. 1 + 0⟧ ^ ⟦β⟧ 
                       = ⟦μ α. 1⟧ ^ ⟦β⟧ 
                       = ⟦1⟧ ^ ⟦β⟧ 
                       =  1 ^ ⟦β⟧
                       =  1
    

    对于其他类型,我们需要使用一些技巧:

    ∀ α. (α, α) -> (α, α) = (∀ α. (α, α) -> α, ∀ α. (α, α) -> α)
                          = (∀ α. α -> α -> α, ∀ α. α -> α -> α)
    
    ⟦∀ α. α -> α -> α⟧ = ⟦μ α. 1 + 1 + 0⟧
                       = ⟦μ α. 2⟧
                       = ⟦2⟧
                       =  2
    
    ⟦∀ α. (α, α) -> (α, α)⟧ = ⟦∀ α. α -> α -> α⟧ * ⟦∀ α. α -> α -> α⟧
                            = 2 * 2
                            = 4
    

    虽然有一个简单的算法可以为我们提供Mogensen-Scott编码类型的居民数量,但我无法想到任何一般算法可以为我们提供任何多态类型的居民数量

    事实上,我有一种强烈的直觉,即计算任何多态类型的居民数量一般都是不可判定的问题。因此,我认为没有任何算法可以为我们提供任何多态类型的居民数量。

    尽管如此,我相信使用Mogensen-Scott编码类型是一个很好的开始。希望这会有所帮助。