- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
[!quote] 关于λ表达式…… 详见λ表达式 。
⚠ 本文导出自Obsidian,可能存在格式偏差(例如链接、Callout等) 本文地址:https://www.cnblogs.com/oberon-zjt0806/p/18710283 。
上一整节我们利用λ符号体系构建了一套表达式系统,从这里开始,我们将正式开始利用这套系统进行代数应用,在进行演算之前,需要先利用符号体系构建一个代数运算系统.
[!note] 命名终究只是命名 虽然我们之前使用了很多诸如(+ x 1)等等这样的形式,但它们只是我们定义的命名,所以无论是x还是+和1,都只是一个记号而已,尽管我们根据以往的经验为这些符号赋予了某些我们所熟知的含义,但在当前的λ演算语境下,这些东西都还没定义过.
为了使λ演算能够具体应用到计算机和程序上,那么就意味着λ代数系统必须能够表示如下两种东西—— 。
也就是说,这些东西要在λ演算中映射为λ表达式(使用表达式来表示).
[!tip] 粗暴地说,Church编码就是一种把数值和运算编码为λ表达式的过程.
- 但注意!Church编码并非唯一的编码方式,还有其他的编码方式,如Scott编码等。
- Church编码的特点在于以数值表示为起点进行编码,并在基础上构建其他编码。
[!abstract] Church-Boolean 编码汇总 为了方便查阅,这里将本节所有的编码定义列出来,正文是比较冗长的推导过程 。
DEF T = λx.λy.x DEF F = λx.λy.y DEF AND = λP.λQ.(P Q P) DEF OR = λP.λQ.(P P Q) DEF NOT = λP.λQ.(P F T)
首先我们需要通过Church编码构建出布尔运算系统。之所以先选择布尔代数,是因为布尔代数的结构简单,性质清晰,比较容易构建.
布尔代数(Boolean Algebra)包含的内容非常简单—— 。
在介绍Church-Boolean中的真假值前,我们先来考察条件选择函数,所谓条件选择函数就是下面这样的一个三元函数—— 。
其中\(c\)是条件值,条件选择函数根据\(c\)的值就在\(x\)和\(y\)中做出选择。可以发现,实际上,这个条件选择函数就对应了大多数编程语言中的三元运算符c ? x : y.
我们将这个运算表示为IF-THEN-ELSE形式,可以表示为—— 。
IF c THEN x ELSE y
可以发现这里分为3个子部—— 。
IF c
:判断c
的条件;THEN x
:当c == true
被满足时,选择x
;ELSE y
:上述条件不成立时,选择và
;至此,我们可以把这三个部分抽象为三个λ表达式.
DEF cond = λc.λx.λy.(c x y)
由于真假值承载于c中,因此我们就利用c来对真假值进行编码.
基于上面的想法,我们就能够通过Church编码定义出逻辑的真值T和假值F。讨论c的情况,根据定义,cond函数应当满足—— 。
cond T x y => λc.λx.λy.(c x y) T x y => λx.λy.(T x y) x y => T x y => x COND F x y => λc.λx.λy.(c x y) T x y => λx.λy.(F x y) x y => F x y => y
观察倒数两步归约,我们发现 。
T x y => x
,那么就要求(T x) y
必须发生η归约.
(T x)
ở giữa约束不生效,可以构建自由表达式(T x) == λb.x
x
的运用,解开约束对,意味着我们需要引入一个新的约束变量T == λa.λb.a
.F x y => y
,那么就要求(F x) y
必须发生β归约.
(F x) == identity == λb.b
x
的运用,解开约束对,引入另外的约束变量 λa
F == λa.λb.b
[!tip] 反归约技巧 我们知道对于运用(f x)进行归约时,会将f中受约束的变量替换为参数x,例如(λa.a x) => x 那么,反过来对于已知的某一表达式x如果想要引入约束,或者把x作为参数提出来,那么就需要引入新的不冲突的约束命名,x => (λy.y x)。 利用这种性质在已知(f x)的情况下可以展开f == λa.(f a) 。
^9b9507 。
经过α转换,将a更名为x,b更名为y,我们就可以得出T和F的定义 。
DEF T = λx.λy.x DEF F = λx.λy.y
这种定义下的T和F被映射为λ函数,因此可以作为一种条件选择函数来运用.
可以将上述定义代入表达式(c x y)通过[[λ表达式#归约 消解|归约]]来证明这个编码的正确性—— 。
[!warning] 注意 归约化简时,不要忘记变量约束的右结合律和函数运用的左结合律 。
(T T F) => (λx.λy.x λx.λy.x λx.λy.y) β|=> (λx.λy.(λx.λy.x) λx.λy.y) α|=> (λy.(λa.λb.a) λx.λy.y) η|=> (λa.λb.a) α|=> (λx.λy.x) => T (F T F) => (λx.λy.y λx.λy.x λx.λy.y) η|=> (λy.y λx.λy.y) β|=> (λx.λy.y) => F // alternatively, ==> identity F => F
接下来要对逻辑运算进行Church编码,这里先给出三种基本逻辑运算的真值表—— 。
MỘT | B | MỘT AND B | MỘT OR B | NOT MỘT |
---|---|---|---|---|
F | F | F | F | T |
F | T | F | T | T |
T | F | F | T | F |
T | T | T | T | F |
XOR、NAND之类的都可以在这三种基本运算的基础上组合出来。所以我们姑且只定义上面三个基本运算即可.
在正式开始之前,我们先考察一个东西——既然T和F都被映射为函数,那么意味着他们可以相互作为函数和参数构成约束对进行运用,那么约束对能否归约,以及归约后的结果是什么,这里给出两个基本函数相互运用的归约结果—— 。
T T => (λx.λy.x) (λx.λy.x) β|=> λy.(λx.λy.x) α|=> λy.(λa.λb.a) => λy.T T F => (λx.λy.x) (λx.λy.y) β|=> λy.(λx.λy.y) α|=> λy.(λa.λb.b) => λy.F [i.e.] T P => λy.P T P Q => P F T => (λx.λy.y) (λx.λy.x) η|=> λy.y => identity F F => (λx.λy.y) (λx.λy.y) η|=> λy.y => identity [i.e.] F P => λy.y => identity F P Q => Q
^6686a8 。
需要注意的是,归约结果中的T和F中的x和y和外层约束的y没有任何关系,而是出现了命名冲突(如果要展开那么需要进行一次α转换),所以实际上这里的T是自由表达式。在上面的归约过程中,我们可以归纳出如下性质—— 。
T
作为函数运用(T P)
(其中P,Q in {T, F}
),那么会通过β归约Sẽx
替换为P
从而得到一个新的函子λy.P
,且Q
不受và
的约束。
λy.P
再作为函数并传入参数Q
构成约束对,那么下一步将发生η归约,消去λy
约束,最终只会剩下P
(T P Q => λy.Q Q => Q
)F
作为函数,那么由于F
củaλx
并没有进行约束,所以先进行η归约,消去λx
约束,最终总会留下λy.y
,好巧不巧地,这正好是恒等函数identity
Q
,由于identity
的性质,或者直接通过β归约替换,则会只留下后面的这个参数P
(F P Q => identity Q => λy.y Q => Q
)![Church T F.svg]] 。
完成上面的工作有助于我们通过Church编码来定义逻辑运算.
首先来看一下合取运算,合取的要求是只有当两个输入均为T,才可以被归约为T,其他情形全部为F—— 。
AND T Q => Q AND T => (F P) AND F Q => F AND F => (T P)
观察上面的形式,对于AND P Q ,我们可以做出如下归纳 。
P==T
giờ,AND P Q => AND T Q => Q
(F P)
,于是AND T Q => F P Q
P==F
giờ,AND P Q => AND F Q => F
(T P)
,于是AND F Q => T P Q
[!question] 麻烦了 目前我们归纳出的结论是AND P == (NOT P) P,然而问题在于我们还没有定义过NOT, 这怎么办呢?
[!tip] 还好 AND满足交换律,也就是说应当有AND P Q == AND Q P 。
通过交换律将AND P Q换成AND Q P,不影响先前的结论,除了讨论对象此时从AND P变成了AND Q.
AND Q P[P:=T] => Q AND Q => (T Q) AND Q P[P:=F] => AND Q F => F AND Q => (F Q) AND Q => (P Q)
终于我们可以得出AND的Church编码—— 。
DEF AND = λP.λQ.(P Q P)
与合取类似,析取也具有交换律,并且我们也可以效仿刚才的过程完成OR的定义,首先考察 。
OR T Q => T OR T => (T P) OR F Q => Q OR F => (F P)
这次无需交换律了,直接替换就能够得到OR的定义—— 。
DEF OR = λP.λQ.(P P Q)
NOT比较特别,因为NOT是一个一元运算,需要单独讨论.
NOT T == NOT λx.λy.x => F == λx.λy.y NOT F == NOT λx.λy.y => T == λx.λy.x
简单来说,输入的参数是选择其中一个,那么NOT的输出总是选择另外一个。考虑到真假值T和F均是通过cond定义的,那么,如果直接反转cond的定义是不是就能够得到相反的输出?
cond == λc.λx.λy.(c x y) ncond == λc.λx.λy.(c y x)
于是我们得到了一种NOT的定义形式 。
DEF NOT1 = λP.λx.λy.(P y x)
这个形式看起来比较底层,我们能不能利用已有的逻辑值来定义呢?
再次考察 cond P —— 。
cond P => λP.λx.λy.(P x y) P => λx.λy.(P x y)
如果考虑将x替换为F,y替换为T,也能达成同样的效果,于是我们进一步提供参数—— 。
cond P F T => λx.λy.(P x y) F T => P F T
于是我们得到了另一种NOT的定义—— 。
DEF NOT2 = λP.(P F T)
通过归约可证明,NOT1 <=> NOT2 。
至此,两个逻辑值和三个基本逻辑运算被定义完毕,Church-Boolean编码完成,可以使用λ表达式进行逻辑演算了.
[!question] 思考 不妨试试用类似的方式定义出更多的逻辑运算,例如异或XOR、与非NAND等…… 。
最后此篇关于从零开始的函数式编程(2)——ChurchBoolean编码的文章就讲到这里了,如果你想了解更多关于从零开始的函数式编程(2)——ChurchBoolean编码的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
Tôi đang cố gắng in một giá trị có kiểu timeval. Thực ra tôi có thể in nó nhưng tôi nhận được cảnh báo sau: Nhiều mã thông báo trong định dạng dòng này '%ld' yêu cầu loại 'long int' nhưng đối số 2 có loại 'struct timeval'
Tôi đang viết trình đầu cuối Unix của riêng mình và tôi gặp sự cố khi thực hiện lệnh: Đầu tiên, tôi nhận dữ liệu đầu vào của người dùng và lưu trữ vào bộ đệm, sau đó tôi tách các từ và lưu trữ chúng vào mảng argv[] của mình. Lệnh IE là "firefox" để khởi chạy tệp được lưu trữ trong
Tôi mới biết đến CUDA. Tôi có một câu hỏi liên quan đến một chương trình đơn giản và hy vọng ai đó có thể nhận ra lỗi của tôi. __toàn cục__ void ADD(float* A, float* B, float* C) { con
Tôi có một câu hỏi chung về lập trình CGI bằng C. Tôi sử dụng máy chủ web nhúng để xử lý giao diện web. Để thực hiện việc này, tôi đã lưu trữ một tệp HTML trên máy chủ. Bao gồm JavaScript và
**Tóm tắt: ** Trong thế giới mã hóa, có nhiều cách viết mang tính nghệ thuật, đây cũng có thể là động lực bên trong khiến một số lập trình viên theo đuổi sự nghiệp lập trình. Bài viết này được chia sẻ từ Cộng đồng Huawei Cloud "[Đồng sáng tạo cư dân đám mây] Sử dụng 4 loại nghệ thuật trong mã để cố gắng khơi dậy lại sự quan tâm của bạn đối với lập trình", tác giả: break
Tôi có một hàm có nhiệm vụ tạo một biến trong đối tượng cha. Điều tôi muốn là hàm này tạo ra biến ở cấp độ mà nó được gọi. createVariable testFunc() [1] "test" > testFunc2() [1]
Đoạn mã sau được sử dụng để thay thế nhiều khoảng trắng liên tiếp bằng 1 khoảng trắng. Mặc dù tôi đã làm được nhưng tôi vẫn bối rối về cách sử dụng dấu ngoặc nhọn. Điều này thực sự hoạt động tốt: #include #include int main() { int ch, la
Tôi đang cố gắng ghi một tập tin vào đĩa và sau đó tự động biên dịch lại tập tin đó. Thật không may, có vẻ như có điều gì đó không ổn và tôi nhận được thông báo lỗi mà tôi vẫn chưa hiểu (tôi là người mới bắt đầu học C :-). Nếu tôi biên dịch hello.c được tạo theo cách thủ công thì mọi thứ sẽ hoạt động tốt phải không? ! #bao gồm
Cách truyền giá trị con trỏ vào mảng cấu trúc; Ví dụ, trên txt tôi có: John Doe;xxxx@hotmail.com;214425532; Mã của tôi: typedef struct Person{
Tôi đã thử viết một số mã để lấy objectID và kết quả là 2B-06-01-04-01-82-31-01-03-01-01. Giá trị này có sai không? // Gửi yêu cầu SNMP SysObjectId
Xin chào, cảm ơn trước vì sự giúp đỡ của bạn, (lưu ý phần bình luận để hiểu rõ hơn: ví dụ, cột chi phí trong ví dụ bên dưới đã được thêm vào câu hỏi này; Simon đã cung cấp một câu trả lời tuyệt vời, nhưng bản thân cột chi phí không xuất hiện trong phản hồi dữ liệu của anh ấy, mặc dù hàm anh ấy cung cấp hoạt động với cột chi phí) Tôi
Tôi tự hỏi liệu có ai có thể gợi ý một số cách để tạo ra một gói phần mềm có thể xử lý các bài toán tối ưu hóa phi tuyến tính, trong đó tôi có thể cung cấp các biến số nguyên cho giải pháp tối ưu hóa không? Vấn đề là phải giảm thiểu một hàm có ràng buộc bằng nhau, tuân theo một số giới hạn trên và dưới. Tôi đã sử dụng 'n
Tôi là người mới bắt đầu học lập trình R và đang cố gắng thêm một cột vào ma trận có 50 cột. Cột mới này sẽ là giá trị trung bình của 10 giá trị đầu tiên trong hàng đó. randomMatrix <- generateMatrix(1,5000,100,
Tôi đọc trong cuốn sách "K&R II C Programming ANSI C" rằng ">>" và "0; nwords--) sum += *buf++; sum = (sum >>
Khi lựa chọn thả xuống thay đổi, tôi muốn: 1) hiển thị một số GUI trên toàn bộ trang web thông qua một div chặn lớp phủ 2) sau đó xử lý một số mã 3) sau đó ẩn lớp phủ. Vấn đề là khi tôi viết logic này trong hàm trình lắng nghe sự kiện, onC được thực thi
Tôi đang thiết kế một máy chủ REST JAX-RS sử dụng Clojure và RESTEasy. Theo tôi hiểu, các ứng dụng được viết bằng họ ngôn ngữ Lisp được xây dựng nhiều hơn dưới dạng "ngôn ngữ dành riêng cho miền" so với các ứng dụng được viết bằng ngôn ngữ mệnh lệnh "truyền thống".
Hiện tại tôi đang thực hiện sáng kiến xây dựng hệ thống giám sát chấm công thay thế. Hiện tại, biểu mẫu người dùng tôi thiết kế trông như thế này: Biểu mẫu người dùng Dấu thời gian Nó hoạt động như thế này: Nhân viên sẽ chọn loại dấu thời gian mà anh ấy/cô ấy sẽ sử dụng: Thời gian bắt đầu, Thời gian chờ, Lần đầu tiên
Tôi là một sinh viên đang cố gắng tự học lập trình, tìm kiếm sự trợ giúp từ các nguồn trực tuyến và những người như bạn. Tôi tìm thấy một bài tập trực tuyến để tạo một chương trình nhỏ để thực hiện việc này: Viết một chương trình đọc các số a và b (số nguyên dài) và liệt kê có bao nhiêu số nằm giữa a và b
Tôi đang cố viết một chương trình shell, khi được cung cấp một đối số, sẽ in ra tên chương trình và mọi từ lẻ trong đối số (tức là không phải các từ chẵn). Tuy nhiên, tôi không nhận được kết quả như mong đợi. Trong khi theo dõi chương trình của mình, tôi nhận thấy rằng mặc dù có những từ kỳ lạ (ví dụ: từ thứ 5, 5%
Tôi chỉ muốn biết liệu có API Java nào cho phép bạn điều khiển đèn LED trên vỏ máy tính để bàn/máy tính xách tay không? Hoặc nếu không thể thì liệu có thể không? Câu trả lời hay nhất Nếu ý bạn là đèn LED ở mặt trước cho biết trạng thái nguồn và trạng thái bận của ổ cứng thì tôi e là không
Tôi là một lập trình viên xuất sắc, rất giỏi!