Haskell:手动评估lambda表达式 - 确定常规类型

时间:2016-01-03 17:56:36

标签: haskell lambda evaluation lambda-calculus

首先,对不起,如果我不是在正确的网站上发布这个,因为我不确定它是否是一个数学问题而不是编程问题,但是因为我&# 39; m在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%了解如何做到这一点,我设计了一种方法。首先,我创建一个模板,它有点像评估表达式的样子。 I.E.如果左侧(' 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。现在,我正在看右侧的构图。我从右到左,我分配了一个 - > b到y因为我不知道它的输入或输出。由于x使用y的结果作为输入,y使用x'再次输出作为输入,x是b - >一个。我可以插入到我的模板中。 正如你所看到的,它与我通过翻译得到的结果并不完全相同,但它只是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 - >湾y使用z的输出,并且本身具有未知输出,因此它得到b - > C。 现在我将它插入到我的模板中,但我仍然缺少f的输入。由于f之后有一个b,我只是假设它也使用b作为输入。 现在有第一个真正的问题:在解释器给出的答案中,f消失了吗?我只能假设因为它使用与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是函数。所以我只是分配一个 - > b到x,这意味着y的输入是b。我此时不知道输出。同样适用于z,因为我不知道y的输出。 因此,当我在模板中输入它们之后,我唯一真正留给我的只是为了填补未知值的空白。由于x需要输入,这意味着它就在它之后。这也意味着它也是z的输入。由于它是z的输入,我可以假设它的输出。唯一需要填写的是z的输出,我只是给它指定一个c,因为我不知道它可能是什么。

正如你所看到的,这根本不是翻译给我的东西。虽然左侧可能仍然有点类似,但我根本不了解右侧发生了什么。为什么是d - > B'不应该是(z(y(x)))的结果,它应该有z的输入/输出吗?

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

1 个答案:

答案 0 :(得分:3)

您可以利用三种基本属性:

  1. 由于currying,\x y -> z相当于\x -> \y -> z
  2. 对于任何x(y),您知道x必须是一个函数,其第一个参数与表达式y的类型相匹配。
  3. 您知道.的类型,即(b -> c) -> (a -> b) -> a -> c。此外,.是右关联的(即a.b.ca.(b.c)相同)。
  4. 考虑到这一点,请考虑您的第一个例子:

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

    显然,它是三个参数的函数,因此它的类型将类似于

    t2 :: ty0 -> ty1 -> ty2 -> ty3
    

    我在这里使用ty0ty3来表示要推断的类型。 ty0x参数的类型,ty1适用于yty2适用于zty3是类型结果值(即表达式y.x.y的类型)。

    我首先确定类型ty3(由表达式y.x.y定义),因为在执行此操作时您还会找到所使用的的类型参数。未使用的参数可以是任何类型:

    1. y.x.y相当于y.(x.y)(由于.的右关联性,请参阅上面的第3项)。因此,您可以先考虑子表达式x.y
    2. 这意味着x :: (b -> c)y :: (a -> b)以及x.y :: a -> c(由于.的类型,再次见上面的#3)。
    3. 我们知道y :: (a -> b)x.y :: a -> c。考虑到这一点,y.(x.y)可以键入检查(即匹配.的类型)的唯一方法是c ~ a,即ca是同类型。
    4. 因此,x :: b -> a(我们的ty0!)和y :: a -> b ( ty1 ) and y。(x.y):: a - > b (what we called ty3`以上)。你可以把它插入我们原始的三参数函数类型'上方。

      t2 :: ty0 -> ty1 -> ty2 -> ty3
      =>
      t2 :: (b -> a) -> (a -> b) -> ty2 -> (a -> b)
      

      ...由于->是右关联的,因此您可以省略最后一个parens(而不是ty2,您当然可以使用c

      让我们在你的上一个例子中尝试相同的策略:

      tm2 = (\z -> \y -> \x -> z.y.x);
      
      1. 这相当于\z y x -> z.y.x(由于讨论,请参阅顶部列表中的#1)。
      2. 这意味着它是tm2 :: ty0 -> ty1 -> ty2 -> ty3形式的另一个三参数函数。同样,我们首先考虑函数的定义来推断类型ty3
      3. 类型ty3是表达式z.y.x的类型,相当于z.(y.x)(由于.的右关联性)。
      4. 所有三个变量必须是满足.类型的函数(参见顶部列表中的#3)。
      5. 所以x :: a -> by :: b -> cy.x :: a -> c
      6. 由此得出z :: c -> d,因此z.y.x :: a -> d
      7. 由于ztm2的第一个参数,y是第二个参数,x是第三个参数,你可以告诉

        tm2 :: (c -> d) -> (b -> c) -> (a -> b) -> (a -> d)