Haskell:手动计算lambda表达式-确定常规类型

Haskell:手动计算lambda表达式-确定常规类型,haskell,lambda,evaluation,lambda-calculus,Haskell,Lambda,Evaluation,Lambda Calculus,首先,如果我没有在正确的网站上发布这篇文章,我很抱歉,因为我不确定这是不是一个数学问题,而不是一个编程问题,但是因为我在Haskell中使用这篇文章,并将结果与Haskell解释器进行比较,我想我应该在这里问一下 所以我基本上是在Haskell中计算lambda表达式,我是手动操作的(为了准备考试,因为我将被迫在纸上操作)。我得到了一些表达式,我必须在计算后写下它们的一般类型。为此,我使用了一个解释器来获得一个稍微正确的答案 特别是,我将计算以下表达式: t2 = ( \x y z ->

首先,如果我没有在正确的网站上发布这篇文章,我很抱歉,因为我不确定这是不是一个数学问题,而不是一个编程问题,但是因为我在Haskell中使用这篇文章,并将结果与Haskell解释器进行比较,我想我应该在这里问一下

所以我基本上是在Haskell中计算lambda表达式,我是手动操作的(为了准备考试,因为我将被迫在纸上操作)。我得到了一些表达式,我必须在计算后写下它们的一般类型。为此,我使用了一个解释器来获得一个稍微正确的答案

特别是,我将计算以下表达式:

t2 = ( \x y z  -> y.x.y );
tx2 = (\x y z -> y.z.z);
tp2 = (\x -> \y -> (x.y.x));
td2 = (\x y z f -> y(z(z(f))));
tm2 = (\z -> \y -> \x -> z.y.x);
由于我不是100%了解如何做到这一点,我设计了一种方法。首先,我创建了一个模板,该模板有点类似于计算表达式的外观。也就是说,如果左侧大小('lambda'd')变量的一部分位于右侧(因为在每种情况下它几乎都是函数组成),那么它就是一个函数。如果不是,它只是一个变量。之后,我尝试尽可能地拟合函数的一般类型,得到了一些半正确的结果,但我确信我仍然犯了一些错误。以下是我的整个评估过程:

t2 = ( \x y z -> y.x.y );

(_ -> _) -> (_ -> _) -> c -> _ -> _

y(x(y))
assume: 
y :: a -> b
x :: b -> a

result: (b -> a) -> (a -> b) -> c -> a -> b
interpreter: (a -> b) -> (b -> a) -> c -> b -> a
z不在右侧,因此在本例中它不是一个函数。我给它赋值为c。现在我看右边的作文。我从右到左,将a->b分配给y,因为我不知道它的输入或输出。由于x使用y的结果作为输入,并且y再次使用x'输出作为输入,因此x是b->a。我可以直接插入到我的模板中。 正如你所看到的,这和我通过解释器得到的结果不完全一样,但它只是a和b被切换,所以它看起来并没有错

tx2 = (\x y z -> y.z.z);

a -> (_ -> _) -> (_ -> _) -> _ -> _

y(z(z))
assume: 
z :: b -> b
y :: b -> c

result: a -> (b -> c) -> (b -> b) -> b -> c
interpreter: a -> (b -> c) -> (b -> b) -> b -> c
同上。因为z在函数合成中使用它自己,所以我假设它具有相同的输入和输出。y使用z的输出作为输入,并且有一些未知的输出,因此c。这似乎与我的翻译相符

tp2 = (\x -> \y -> (x.y.x));

(_ -> _) -> (_ -> _) -> _ -> _

x(y(x))
assume: 
x :: a -> b
y :: b -> a

result: (a -> b) -> (b -> a) -> a -> b
interpreter: (a -> b) -> (b -> a) -> a -> b
与第一个示例基本相同,只是我没有未使用的lambda变量

td2 = (\x y z f -> y(z(z(f))));

a -> (_ -> _) -> (_ -> _) -> (_ -> _) -> _ -> _

y(z(z(f)))
assume:
f :: _ -> b
z :: b -> b
y :: b -> c

assume: a -> (b -> c) -> (b -> b) -> (_ -> b) -> b -> c
result: a -> (b -> c) -> (b -> b) -> (b -> b) -> b -> c
interpreter: a -> (b -> c) -> (b -> b) -> b -> c
在这种情况下,除了x以外的一切都是函数。f的输入最初我并不知道,我只是把它留为空。z在合成中使用f的输出和它自己的输出,所以我只分配它b->b。y使用z的输出,并且本身有一个未知的输出,所以它得到b->c。 现在我将它插入到我的模板中,但仍然缺少f的输入。因为f后面有一个b,所以我假设它也使用b作为输入。 现在有了第一个真正的问题:在解释器给出的答案中,f消失在哪里了?我只能假设,因为它使用与z相同的输入/输出,并且基本上是由z组成的,所以它只是简化为一个b->b,但我不确定这一点

tm2 = (\z -> \y -> \x -> z.y.x);
tm2 = (\z y x -> z.y.x);

(_ -> _) -> (_ -> _) -> (_ -> _) -> _ -> _

z(y(x))
assume:
x = a -> b
y = b -> _
z = _ -> _

assume: (_ -> _) -> (b -> _) -> (a -> b) -> _ -> _
result?: (a -> c) -> (b -> a) -> (a -> b) -> a -> c
interpreter: (a -> b) -> (c -> a) -> (d -> c) -> d -> b
这里是所有函数的分界点:z、y和x是函数。我只是把a->b赋值给x,这意味着y的输入是b。此时我不知道输出结果。z也是一样,因为我不知道y的输出。 因此,在我将它们输入模板后,唯一真正留给我的就是填补未知值的空白。因为x需要a作为输入,这意味着它后面有一个a。这意味着它也是z的输入。因为它是z的输入,所以我可以假设它是y的输出。唯一需要填写的是z的输出,我只给它赋值一个c,因为我不知道它可能是什么

正如你所看到的,这根本不是翻译给我的。虽然左手边可能还是有些相似,但我根本不明白右手边会发生什么。为什么是d->b?它不应该是(z(y(x))的结果吗?它应该有z的输入/输出


提前感谢您为我提供的任何帮助。

您可以利用以下三个基本属性:

  • 由于货币化,
    \x y->z
    相当于
    \x->\y->z
  • 对于任何
    x(y)
    ,您都知道
    x
    必须是一个函数,并且它的第一个参数与表达式
    y
    的类型匹配
  • 您知道
    的类型,即
    (b->c)->(a->b)->a->c
    。此外,
    是右关联的(即
    a.b.c
    a.(b.c)
    相同)
  • 考虑到这一点,考虑你的第一个例子:

    t2 = ( \x y z  -> y.x.y );
    
    tm2 = (\z -> \y -> \x -> z.y.x);
    
    显然,它是三个参数的函数,所以它的类型类似于

    t2 :: ty0 -> ty1 -> ty2 -> ty3
    
    我在这里使用
    ty0
    ty3
    来表示要推断的类型
    ty0
    x
    参数的类型,
    ty1
    y
    ty2
    z
    的类型,
    ty3
    是结果值的类型(即表达式
    y.x.y

    我首先要确定类型
    ty3
    (由表达式
    y.x.y
    定义),因为这样做的同时,您还可以找到所用参数的类型。未使用的参数可以有任何类型:

  • y.x.y
    相当于
    y.(x.y)
    (由于
    的右关联性,请参见上文第3项)。因此,您可以从考虑子表达式
    x.y
    开始
  • 这意味着
    x::(b->c)
    y:(a->b)
    ,因此
    x.y::a->c
    (由于
    的类型,再次参见上文第3条)
  • 所以我们知道
    y::(a->b)
    x.y::a->c
    。记住这一点,
    y.(x.y)
    可以进行类型检查(即匹配
    的类型)的唯一方法是当
    c~a
    时,即
    c
    a
    是同一类型
  • 因此,
    x::b->a
    (我们的
    ty0
    !)和
    y::a->b
    ty1
    )和
    y.(x.y)::a->b
    (我们称之为
    ty3`ab
    
    tm2 = (\z -> \y -> \x -> z.y.x);
    
    tm2 :: (c -> d) -> (b -> c) -> (a -> b) -> (a -> d)