系统F中的邮递功能

时间:2019-05-25 23:25:58

标签: lambda-calculus type-theory system-f

让我们定义列表类型

list = forall 'a, 'x. ('a -> 'x -> 'x) -> 'x -> 'x 

例如

nil = Λ'a . Λ'x . λ(c : 'a -> 'x -> 'x) . λ(e : 'x) . e
cons = Λ'a . Λ'x . λ(head : 'a) . λ(tail : list 'a 'x) . λ(c : 'a -> 'x -> 'x) . λ(e : 'x) . c head (tail c e)

我正在尝试定义类型为zip的函数

zip : forall 'a, 'b, 'c, 'x. ('a -> 'b -> 'c) -> list 'a 'x -> list 'b 'x -> list 'c 'x 

这很直观

zip (+) [1,2,3] [4,5,6] = [5,7,9]
zip (λa . λb . a) [1,2] [2,3,4] = [1,2]
zip (λa . λb . a) [2,3,4] [1,2] = [2,3]

请注意,它会截断较长的列表以适合较短的列表。

我在这里遇到的主要问题是我无法一次“迭代”两个列表。如何在系统F中实现这样的功能?甚至有可能吗?

1 个答案:

答案 0 :(得分:0)

好的,我设法为其编写了解决方案。首先,让我们定义助手option类型:

option = forall 'a, 'x. ('a -> 'x) -> 'x -> 'x

其中有两个构造函数:

none = Λ'a . Λ'x . λ (onsome : 'a -> 'x) . λ (onnone : 'x) . onnone
some = Λ'a . Λ'x . λ (elem : 'a) . λ (onsome : 'a -> 'x) . λ (onnone : 'x) . onsome elem

下一步是提取列表中的headtail的函数。 head将返回option 'elemtype来处理空列表情况,但是tail只会在空列表上返回空列表(类似于教会数字的前任功能)

head = Λ 'a . λ (l : list 'a) . l (λ (elem : 'a) . λ (p : option 'a) . some elem) none
tail = Λ 'a . λ (l : list 'a) .
    pair_first 
       ( l (λ (elem : 'a) . λ (p : pair (list 'a) (list 'a)) .
               make_pair (list 'a) (list 'a) 
                  (pair_second (list 'a) (list 'a) p) 
                  (cons 'a elem (pair_second (list 'a) (list 'a) p))) 
           (make_pair (list 'a) (list 'a) (nil 'a) (nil 'a)))

head的想法是,我们从空列表上以none开始的列表开始聚合,对于左侧的每个新元素,我们将此元素设置为some包装的结果保持打字。 另一方面,tail不需要明确定义option,因为在空列表的情况下,我们可能只返回一个空列表。它看起来很丑陋,但使用的方法与自然数的前身相同。我假设pair接口是已知的。

接下来,让我们定义listmatch函数,该函数将在给定列表上进行模式匹配

listmatch = Λ 'a . Λ 'x . λ (l : list 'a) . λ (oncons : 'a -> list 'a -> 'x) . λ (onnil : 'x) .
    (head 'a l)
      (λ (hd : 'a) . oncons hd (tail 'a l))
      onnil

此功能可帮助我们区分空列表和非空列表,并在销毁后执行一些操作。

几乎最后,我们希望拥有foldl2函数,该函数给定函数f,空大小写em和两个列表[a,b,c][x,y]返回类似这:f(f(em a x) b y)(将列表缩小到剪下尾巴的较短的那个)。

可以定义为

foldl2 =
  Λ 'a . Λ 'b . Λ 'c .
  λ (f : 'c -> 'a -> 'b -> 'c) . λ (em : 'c) . λ (la : list 'a) . λ (lb : list 'b) .
  pair_first 'c (list 'b)
    ((reverse 'a la)
      ( λ (el : 'a) . λ (p : pair 'c (list 'b)) . 
        listmatch 'a (pair 'c (list 'b)) (pair_second 'c (list 'b) p)
          (λ (hd : 'a) . λ (tl : list 'a) .
            make_pair 'c (list 'b) 
              (f (pair_first 'c (list 'b) p) el hd)
              tl)
          (make_pair 'c (list 'b) (pair_first 'c (list 'b) p) (nil 'a))
      )
      (make_pair 'c (list 'b) em lb))

之后,zip就在我们手中:

zip = 
  Λ 'a . Λ 'b . Λ 'c .
  λ (f : 'a -> 'b -> 'c) . λ (la : list 'a) . λ (lb : list 'b) .
  reverse 'c
    (foldl2 'a 'b 'c
      (λ (lt : 'c) . λ (a : 'a) . λ (b : 'b) . cons 'c (f a b) lt)
      (nil 'c) la lb)