首先,对不起,如果我不是在正确的网站上发布这个,因为我不确定它是否是一个数学问题而不是编程问题,但是因为我&# 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的输入/输出吗?
提前感谢您提供给我的任何帮助。
答案 0 :(得分:3)
您可以利用三种基本属性:
\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 );
显然,它是三个参数的函数,因此它的类型将类似于
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 ) 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);
\z y x -> z.y.x
(由于讨论,请参阅顶部列表中的#1)。tm2 :: ty0 -> ty1 -> ty2 -> ty3
形式的另一个三参数函数。同样,我们首先考虑函数的定义来推断类型ty3
。ty3
是表达式z.y.x
的类型,相当于z.(y.x)
(由于.
的右关联性)。.
类型的函数(参见顶部列表中的#3)。x :: a -> b
,y :: b -> c
,y.x :: a -> c
。z :: c -> d
,因此z.y.x :: a -> d
。由于z
是tm2
的第一个参数,y
是第二个参数,x
是第三个参数,你可以告诉
tm2 :: (c -> d) -> (b -> c) -> (a -> b) -> (a -> d)