Haskell中高阶函数的Lambda表达式
接下来,Haskell中的所有内容都是λ演算:像fx=x+1这样的函数可以在Haskell中写成f=\x->x+1,在λ表达式中写成λx.x+1 对于像map::a->b->[a]->[b]这样的高阶函数,λ表达式是什么?函数$:a->b->a->b的或λ表达式? 那么函数列表呢,例如f:[a->b]?一个具体的例子可以是h=map\fx->fx5[-,+]。那么λ表示法类似于h=mapλfx.fx5[λab.a-b,λab.a+b]? 我只是熟悉alpha转换、beta缩减等过程,但如果您将函数列表分解为λ项,则会非常感激,无需简化 谢谢。首先 Haskell中的一切都是λ-微积分 这是不正确的。Haskell有许多与非类型λ演算中的某些东西不对应的特性。也许他们的意思是它可以被编译成λ-演算,但这是很明显的,用“任何图灵完全语言…”jadda jadda 像map::a->b->[a]->[b]这样的高阶函数的λ表达式是什么 这里有两个不相关的问题。“高阶函数”部分对于直接λ转换来说根本没有问题,正如前面的评论所说Haskell中高阶函数的Lambda表达式,haskell,functional-programming,higher-order-functions,lambda-calculus,Haskell,Functional Programming,Higher Order Functions,Lambda Calculus,接下来,Haskell中的所有内容都是λ演算:像fx=x+1这样的函数可以在Haskell中写成f=\x->x+1,在λ表达式中写成λx.x+1 对于像map::a->b->[a]->[b]这样的高阶函数,λ表达式是什么?函数$:a->b->a->b的或λ表达式? 那么函数列表呢,例如f:[a->b]?一个具体的例子可以是h=map\fx->fx5[-,+]。那么λ表示法类似于h=mapλfx.fx5[λab.a-b,λab.a+b]? 我只是熟悉alpha转换、beta缩减等过程,但如果您将函
($) = \f -> \x -> f x -- λf.λx.fx
或者
($) = \f x -> f x
($) = \f -> f -- by η-reduction
在Haskell中,我们将进一步缩短为$=id
另一件事是map是一个定义在代数数据类型上的递归函数,将其转换为非类型λ演算将使我们远离Haskell。将其转换为包含模式匹配case和let绑定的λ-flavor更具指导意义,这实际上是GHC在编译程序时所做的事情。想出来很容易
map = \f l -> case l of
[] -> []
(x:xs) -> f x : map f xs
…或避免在顶级绑定上递归
map = \f -> let go l = case l of
[] -> []
(x:xs) -> f x : go xs
in go
我们不能像那样摆脱let,因为λ演算不直接支持递归。但是递归也可以用不动点组合表示;与非类型λ-演算不同,我们不能自己定义Y-组合子,但我们可以假设它是一个基元。结果证明,这与递归let绑定几乎完全相同,然后立即对其进行评估:
map = \f -> fix ( \go l -> case l of
[] -> []
(x:xs) -> f x : go xs )
要为其编写λ-风格的语法
map = λf.fix(λg.λl.{l? []⟼[]; (x:s)⟼fx:gs})
首先
Haskell中的一切都是λ-微积分
这是不正确的。Haskell有许多与非类型λ演算中的某些东西不对应的特性。也许他们的意思是它可以被编译成λ-演算,但这是很明显的,用“任何图灵完全语言…”jadda jadda
像map::a->b->[a]->[b]这样的高阶函数的λ表达式是什么
这里有两个不相关的问题。“高阶函数”部分对于直接λ转换来说根本没有问题,正如前面的评论所说
($) = \f -> \x -> f x -- λf.λx.fx
或者
($) = \f x -> f x
($) = \f -> f -- by η-reduction
在Haskell中,我们将进一步缩短为$=id
另一件事是map是一个定义在代数数据类型上的递归函数,将其转换为非类型λ演算将使我们远离Haskell。将其转换为包含模式匹配case和let绑定的λ-flavor更具指导意义,这实际上是GHC在编译程序时所做的事情。想出来很容易
map = \f l -> case l of
[] -> []
(x:xs) -> f x : map f xs
…或避免在顶级绑定上递归
map = \f -> let go l = case l of
[] -> []
(x:xs) -> f x : go xs
in go
我们不能像那样摆脱let,因为λ演算不直接支持递归。但是递归也可以用不动点组合表示;与非类型λ-演算不同,我们不能自己定义Y-组合子,但我们可以假设它是一个基元。结果证明,这与递归let绑定几乎完全相同,然后立即对其进行评估:
map = \f -> fix ( \go l -> case l of
[] -> []
(x:xs) -> f x : go xs )
要为其编写λ-风格的语法
map = λf.fix(λg.λl.{l? []⟼[]; (x:s)⟼fx:gs})
警告:以下代码包含一个错误,导致定义结果为方程式map fx:xs==fx:map f map fxs,据我所知
继续
Y是一个定点组合器:
Y = λg.(λx.g(xx))(λx.g(xx)) -- Yg == g(Yg)
-- MAP(f) == (λl.l(NIL)(λxs.CONS(fx)(MAP(f)s)))
列表是lambda术语,它接受两个要适当应用的参数,第一个是在列表为空的情况下,第二个是在列表为空的情况下:
-- constructs an empty list
NIL = λnc.n
-- constructs a non-empty list from its two constituent parts
CONS = λadnc.ca(dnc)
因此,例如,CONS1CONS2NIL返回的术语将由MAPf转换为
警告:以下代码包含一个错误,导致定义结果为方程式map fx:xs==fx:map f map fxs,据我所知
继续
Y是一个定点组合器:
Y = λg.(λx.g(xx))(λx.g(xx)) -- Yg == g(Yg)
-- MAP(f) == (λl.l(NIL)(λxs.CONS(fx)(MAP(f)s)))
列表是lambda术语,它接受两个要适当应用的参数,第一个是在列表为空的情况下,第二个是在列表为空的情况下:
-- constructs an empty list
NIL = λnc.n
-- constructs a non-empty list from its two constituent parts
CONS = λadnc.ca(dnc)
因此,例如,CONS1CONS2NIL返回的术语将由MAPf转换为
在lambda演算中如何表示列表?$=\f->\x->fx变为λf.λx.fx。这只是同一事物的不同语法。如果我错了,请纠正我,但当你写λf.λx.fx时,它意味着一个返回fx的函数?Whi
le$::a->b->a->b接受一个函数λx。termsOfx并返回另一个函数或λx。termsOfx?抽象数据类型仅预定义类型构造函数和析构函数。特别是::and[]是两个常量cons::α的语法糖→ [α] → [α] 零::[α]。列表[1,2,3]只是一个术语1::2::3::[]或者具有更少的语法糖分cons1,cons2,cons3,nil。在非类型化的lambda演算中,高阶函数只是一个函数,因为你不能说任何特定变量代表什么;一切都是按照抽象应用程序之间的相互关系进行编码的。类型化lambda演算是另一回事。在lambda演算中如何表示列表?$=\f->\x->fx变为λf.λx.fx。这只是同一事物的不同语法。如果我错了,请纠正我,但当你写λf.λx.fx时,它意味着一个返回fx的函数?而$::a->b->a->b接受一个函数λx。termsOfx并返回另一个函数或λx。termsOfx?抽象数据类型仅预定义类型构造函数和析构函数。特别是::and[]是两个常量cons::α的语法糖→ [α] → [α] 零::[α]。列表[1,2,3]只是一个术语1::2::3::[]或者具有更少的语法糖分cons1,cons2,cons3,nil。在非类型化的lambda演算中,高阶函数只是一个函数,因为你不能说任何特定变量代表什么;一切都是按照抽象应用程序之间的相互关系进行编码的。类型化lambda演算是另一回事。