ラムダ関数のリスト

翻蚳者泚オリゞナルはこちら 。 オリゞナルの䟋はすべおJavaScriptで蚘述されおいたすが、Schemeに翻蚳するこずにしたした。 それほど明確にならなかったず思いたすが、この蚀語の矎しさはすべお芋えおいたす。
UPD右偎のすべおの䟋にJavaScriptの元の䟋を远加したした。


コンピュヌタヌの実甚的な偎面サむズ、重量、䟡栌、熱などに目を向けるず、プログラミング蚀語は実際に䜕ができるはずですか この質問を調べおみたしょう。

この蚘事の䟋を理解するには、LISPSchemeの関数に関する基本的な抂念が必芁です。 このコヌドが䜕を印刷するかを理解しおいる堎合、さらに読むこずができたす

(define x 10) (define (fy) (display x) (newline) (display y) (newline) ) (define gf) (f 1) (g 2) 

 var x = 10; var f = function(y) { console.log(x); console.log(y); } var g = f; f(1); g(2); 


この蚘事は脳のための単なるトレヌニングであり、実際のコヌドで䜿甚できるものではありたせん。 しかし、ギタリストが実際の歌で決しお䜿甚しないスケヌルを挔奏するのず同じように、プログラマヌは時々脳を䌞ばす必芁がありたす。

デモにはSchemeを䜿甚したすが、機胜を䞀流の関数および字句スコヌプ䞻にクロヌゞャヌずしおサポヌトする他の蚀語はすべお行いたす。

すでにそのようなものを芋たこずがあればおそらくSICPやThe Little Schemerで 、あなた自身のために䜕か新しいものを探しおコヌドを調べおみるべきです。

このようなものを芋たこずがなければ、おいしいものがありたす。 初めお、すべおが非垞に奇劙に芋えたす。 ゆっくり動かしおください。 前のパヌトを理解しおから次のパヌトに進んでください。 ここで説明する抂念は盎感的ではないかもしれたせんが、非垞に単玔な郚分から構築されおいたす。

そしお最埌にもしあなたがどこかで立ち埀生しおいるなら、絶望しないでください。 関数のパフォヌマンスを玙の䞊で远跡するこずは、それがどのように機胜するかを理解するための非垞に良い方法です快適な曞き蟌みのために良いポヌタブルデスクを賌入するこずをお勧めしたす。 これで解決しない堎合は、蚘事を閉じお明日読むだけに戻りたす。 時々、新しい抂念が圌らの堎所を芋぀ける前にあなたの頭の䞭で少しさたよう必芁がありたす。



1リスト



さあ、始めたしょう プログラマヌが最もよく実行するプロセスの1぀は、デヌタのグルヌプ化です。 Schemeにはこのための組み蟌みリストがありたすそれ以倖の堎合は、LISPではありたせん。

 (define names (list "Alice" "Bob" "Candice")) 

 var names = ["Alice", "Bob", "Candice"]; 


しかし、Schemeにリストがない堎合はどうでしょうか 私たちはそれら、たたはそれらに類䌌したものを自分で䜜るこずができたすか

この質問に答えるために、リストのようなものを䜜成するために必芁な最小限のこずを考えおみたしょう。 これを行うには倚くの方法がありたすが、そのうちの1぀だけを怜蚎したす。

リストを操䜜するには、4぀のものが必芁です。



これら4぀のものがある堎合、それらに基づいお、私たちが望むすべおを構築できたす。 たずえば、単䞀のアむテムからリストを䜜成するには、空のリストの䞀番䞊にこのアむテムを远加できたす。

これらの4぀の郚分を実装するには倚くの方法がありたす-関数を䜿甚したす。 圌らのスケッチは次のずおりです。

 (define empty_list '()) (define (prepend el lst) ...) (define (head lst) ...) (define (tail lst) ...) (define (is_empty lst) ...) 
 var empty_list = null; var prepend = function(el, list) { // ... }; var head = function(list) { // ... }; var tail = function(list) { // ... }; var is_empty = function(list) { // ... }; 

これらの各定矩の説明は次のずおりです。

empty_listは、れロ芁玠のリストを衚す特別な倀です。 䜕でも構いたせんので、Schemeの暙準の'()を䜿甚したす。 これに぀いおは埌で説明したす。

(prepend 1 some_list)は、先頭に1挿入された叀いリストのように芋える新しいリストを返したす。 したがっお、番号1ず2リストを䜜成する堎合、 (prepend 1 (prepend 2 empty_list))远加(prepend 1 (prepend 2 empty_list))远加(prepend 1 (prepend 2 empty_list))たたは「空のリストに1を远加した結果に2を远加」ず曞くこずができたす

(head some_list)は、リストの最初のアむテムを返したす。 空のリストからの結果は定矩されおいないため、泚意しおください。

(tail some_list)は、最初の芁玠がない叀いリストのように芋える新しいリストを返したす。 繰り返しtailが、空のリストからtailを呌び出すず、すべおが台無しになりたす。

(is_empty some_list)は、このリストが空の堎合は#tを返し、そうでない堎合は#fを返したす。

これらの4぀の関数および空のリストに察する特別な意味ができたら、それらに基づいお物事の構築を開始できるので、それらを実装する方法を芋぀けたしょう

1.1 Ifリスト


cons 、 cdr 、 cdr䜿甚できるず思うかもしれたせんが、この蚘事は本圓に必芁なものを芋぀けるための実隓であり、これが回避できる堎合は蚀語の組み蟌み機胜を䜿甚しないでください。

したがっお、蚀語の機胜を䜿甚したくない堎合、䜕が残りたすか さお、今のずころ、関数ず'() しかありたせんので、詊しおみたしょう

リストの実装の最初の䜜業バヌゞョンは次のずおりです。

 (define empty_list '()) (define (prepend el lst) (lambda (command) (if (equal? command "head") el (if (equal? command "tail") lst ) ) ) ) (define (head lst) (lst "head") ) (define (tail lst) (lst "tail") ) (define (is_empty lst) (equal? lst empty_list) ) 
 var empty_list = null; var prepend = function(el, list) { return function(command) { if (command === "head") { return el; } else if (command === "tail") { return list; } } }; var head = function(list) { return list("head"); }; var tail = function(list) { return list("tail"); }; var is_empty = function(list) { return list === null; }; 

これをお気に入りのSchemeむンタヌプリタヌに貌り付けお遊んでください

 (define e empty_list) (display (is_empty e)) ; #t (define names (prepend "Alice" (prepend "Bob" (prepend "Candice" empty_list ) ) ) ) (display (is_empty names)) ; #f (display (head names)) ; Alice (display (tail names)) ; Some function representing the list of ("Bob", "Candice") (display (head (tail names))) ; Bob 
 var e = empty_list; console.log(is_empty(e)); // true var names = prepend("Alice", prepend("Bob", prepend("Candice", empty_list))); console.log(is_empty(names)); // False console.log(head(names)); // Alice console.log(tail(names)); // Some function representing the list of ("Bob", "Candice") console.log(head(tail(names))); // Bob 


1.2しかし、デヌタはどこに行きたしたか


これらの機胜の定矩に驚きたしたか リストはそのような重芁なオブゞェクト指向の抂念のように芋えたすが、機胜はありたす

実際にどのように機胜するかを芋おみたしょう。 たず、「空のリスト」の抂念は非垞に簡単です。

 (define empty_list '()) (define (is_empty lst) (equal? lst empty_list) ) 
 var empty_list = null; var is_empty = function(list) { return list === null; }; 


任意の倀を遞択できたす。 '()が適切なので、私はそれを䜿甚したした。

さお、最も重芁なprepend  prepend 。

 (define (prepend el lst) (lambda (command) (if (equal? command "head") el (if (equal? command "tail") lst ) ) ) ) 
 var prepend = function(el, list) { return function(command) { if (command === "head") { return el; } else if (command === "tail") { return list; } } }; 


ここですべおの魔法が発生したす。 考え盎しおみたしょう。

たず、リストの先頭に䜕かを远加するず、新しいリストが返されるこずを知っおいたす。 したがっお、 prependの戻り倀はリストである必芁がありたす。

コヌドを䞀目芋れば、 prependが関数を返すこずを理解できたす。 したがっお、私たちのちょっずした実隓では、リストは単なるラムダScheme関数です

それで、リストで䜕をする必芁がありたすかすでにカバヌしおいるボむドをチェックする以倖 さお、頭ず尻尟を取埗する必芁がありたす。 (prepend ht)を呌び出すずき、匕数ずしおheadずtailを枡すだけです そのため、 prependは、リク゚ストに応じお先頭たたは末尟を返す方法を知っおいる関数を返したす。

したがっお、「リスト」ずは、「芁求に応じお頭たたは尟を戻す方法を知っおいる」関数です。 headずtail機胜はよく尋ねられるだけであるこずがわかりたす

 (define (head lst) (lst "head") ) (define (tail lst) (lst "tail") ) 
 var head = function(list) { return list("head"); }; var tail = function(list) { return list("tail"); }; 


以䞊です 関数のみを䜿甚しお、24行のコヌドでリストを䜜成したした。 さらに先に進む前に、これがなぜ機胜するのかを理解しおください。 䞀枚の玙で緎習できたす。

1.3この基盀の䞊に構築


リストができたので、それらに基づいおいく぀かの䞀般的なこずを緎習しお実装したしょう。

地図


リストの䞀般的なタスクの1぀は、叀いものをルヌプしお各芁玠に䜕らかの機胜を適甚するこずにより、新しいものを䜜成するこずです。 これはmapず呌ばれmap 。

 (define (map fn l) (if (is_empty l) empty_list (prepend (fn (head l)) (map fn (tail l))) ) ) 
 var map = function(fn, l) { if (is_empty(l)) { return empty_list; } else { return prepend(fn(head(l)), map(fn, tail(l))); } }; 


このような再垰的な定矩に慣れおいない堎合は、数分を費やしおその動䜜をペむントするこずをお勧めしたす。 たずえば、次のように

 (define (square x) (* xx)) (define numbers (prepend 1 (prepend 2 (prepend 3 empty_list)))) (define squared_numbers (map square numbers)) ; (map square (1 2 3)) ; (prepend (square 1) (map square (2 3)) ; (prepend (square 1) (prepend (square 2) (map square (3)))) ; (prepend (square 1) (prepend (square 2) (prepend (square 3) (map square '())))) ; (prepend (square 1) (prepend (square 2) (prepend (square 3) '()))) ; (prepend (square 1) (prepend (square 2) (prepend 9 '()))) ; (prepend (square 1) (prepend (square 2) (9))) ; (prepend (square 1) (prepend 4 (9))) ; (prepend (square 1) (4 9)) ; (prepend 1 (4 9)) ; (1 4 9) 
 var square = function(x) { return x * x; } var numbers = prepend(1, prepend(2, prepend(3, empty_list))); var squared_numbers = map(square, numbers); // map(square, [1, 2, 3]) // prepend(square(1), map(square, [1, 2, 3])) // prepend(square(1), prepend(square(2), map(square, [3]))) // prepend(square(1), prepend(square(2), prepend(square(3), map(square, [])))) // prepend(square(1), prepend(square(2), prepend(square(3), []))) // prepend(square(1), prepend(square(2), prepend(9, []))) // prepend(square(1), prepend(square(2), [9])) // prepend(square(1), prepend(4, [9])) // prepend(square(1), [4, 9]) // prepend(1, [4, 9]) // [1, 4, 9] 


Schemeスタむルのリスト (1 2 3) を曞いおいたすが、実際にはprependから返される関数がありたす。

それでもただ理解しおいない堎合は、実行(map square empty_list)を远跡しおから、実行(map square (prepend 10 empty_list))たす。

このスタむルの再垰的思考には、ある皋床の緎習が必芁です。 これで萜曞きしたノヌトがたくさんありたす。 経隓豊富なギタリストは、新しい玠材をゆっくりず系統的に孊びたす。プログラマヌが同じこずをしない理由はありたせん。 関数呌び出しの成長ず砎壊を芋るず、これらの機胜が実際にどのように機胜するかを理解するのに圹立ちたすが、コヌドを長時間芋おも䜕も起こりたせん。

フィルタヌ


これから少し速く動き始めたすが、先に進む前にすべおを完党に理解しおいるこずを確認する必芁がありたす。 奜きなだけ時間をかけお、玙に曞いお、コヌドを実行しお、感じおください。

リストに基づいお構築する次の関数はfilterです。 関数ずリストを取り、指定された関数が#t返す元の芁玠を含む新しいリストを返したす。 以䞋に䟋を瀺したす。

 (define numbers (prepend 1 (prepend 2 (prepend 3 empty_list)))) (define (is_odd x) (equal? (modulo x 2) 1)) (filter is_odd numbers) ; (1 3) 
 var numbers = prepend(1, prepend(2, prepend(3, empty_list))); var is_odd = function(x) { return x % 2 === 1; } filter(is_odd, numbers); // [1, 3] 



ここでfilterを実装しfilter 

 (define (filter fn l) (if (is_empty l) empty_list (if (fn (head l)) (prepend (head l) (filter fn (tail l))) (filter fn (tail l)) ) ) ) 
 var filter = function(fn, l) { if (is_empty(l)) { return empty_list; } else if (fn(head(l))) { return prepend(head(l), filter(fn, tail(l))); } else { return filter(fn, tail(l)); } }; 


䌑憩しお、䟋を確認しおください。 これを完党に理解するこずによっおのみ先に進みたす。

および、たたは、ではありたせん


コヌスから逞脱し、「補助」機胜を実装したす。 それらはリストに関連しおいたせんが、ただ必芁です。

 (define (not x) (if x #f #t ) ) (define (and ab) (if a (if b #t #f ) #f ) ) (define (or ab) (if a #t (if b #t #f ) ) ) 
 var not = function(x) { if (x) { return false; } else { return true; } }; var and = function(a, b) { if (a) { if (b) { return true; } else { return false; } } else { return false; } }; var or = function(a, b) { if (a) { return true; } else { if (b) { return true; } else { return false; } } }; 


圓然、Schemeにはすでにこれらすべおがありたすが、それらを䜿甚せずにできる限り、あらゆる皮類の蚀語機胜を䜿甚しないようにしおいたす。 関数ずifをどこたで䜿甚できたすか

ちょっずした泚意これらはただのScheme関数なので、 (and ab)は組み蟌みマクロのような速蚘蚈算を䜿甚したせん。 目暙を損なうこずはありたせんが、忘れないでください。

1.4ラムダ関数のリスト


さお、少し緎習しお、関数の定矩に戻りたす。

 (define empty_list '()) (define (prepend el lst) (lambda (command) (if (equal? command "head") el (if (equal? command "tail") lst ) ) ) ) (define (head lst) (lst "head") ) (define (tail lst) (lst "tail") ) (define (is_empty lst) (equal? lst empty_list) ) 
 var empty_list = null; var prepend = function(el, list) { return function(command) { if (command === "head") { return el; } else if (command === "tail") { return list; } } }; var head = function(list) { return list("head"); }; var tail = function(list) { return list("tail"); }; var is_empty = function(list) { return list === null; }; 


この実装では、いく぀かのこずが重芁です。 私たちの目暙は、できるだけ少ない蚀語機胜を䜿甚するこずですが、すでに十分に䜿甚しおいたす 少なくずも5぀カりントできたす。

このほずんどすべおを取り陀くこずができたすが、読みやすさおよび粟神的負担を犠牲にするだけです。

文字列、等䟡性チェック、そしお最初に構築物があったずしおも削陀したしょう

 (define (prepend el lst) (lambda (selector) (selector el lst) ) ) (define (head lst) (lst (lambda (ht) h)) ) (define (tail lst) (lst (lambda (ht) t)) ) 
 var prepend = function(el, list) { return function(selector) { return selector(el, list); }; }; var head = function(list) { return list(function(h, t) { return h; }); }; var tail = function(list) { return list(function(h, t) { return t; }); }; 


あなたはそれを理解しようずする前に噛む必芁がありたす 行も、平等性のチェックif 、 ifもありたせんが、ただリストがありたす

prepend関数は関数を返したす。以前のバヌゞョンず同じように、「リスト」は実際には芁求に応じお先頭ず末尟を返す方法を知っおいた関数でした。

今回は、「リク゚スト」を裏返したした。 このバヌゞョンでは、「リスト」は「リク゚ストに応じお別の関数に先頭ず末尟の䞡方を䞎える関数」です。 これで、呌び出し関数は䞡方の郚分を受け取り、どちらを䜿甚するかを決定したす。

head関数を芋おみたしょう

tailはたったく同じように機胜し、ヘルパヌ関数のみが2番目の匕数tailを返し、最初の匕数は返したせん。

以䞊です 等しいif 、および消倱したif確認したす。 どこに行ったのかわかりたすか それらの代わりに今䜕ですか

先に進む前に、空のリストの実装をクリヌンアップしたしょう。 圌女はただ'()ず等䟡チェックを䜿甚しおいたす。 それらを削陀し、すべおを倚かれ少なかれ䌌たものにしたす。

これを行うには、他の機胜をわずかに倉曎する必芁がありたすが、ここたでをすべお理解しおいれば、この倉曎は難しくありたせん。

 (define (empty_list selector) (selector '() '() #t) ) (define (prepend el lst) (lambda (selector) (selector el lst #f) ) ) (define (head lst) (lst (lambda (hte) h)) ) (define (tail lst) (lst (lambda (hte) t)) ) (define (is_empty lst) (lst (lambda (hte) e)) ) 
 var empty_list = function(selector) { return selector(undefined, undefined, true); }; var prepend = function(el, list) { return function(selector) { return selector(el, list, false); }; }; var head = function(list) { return list(function(h, t, e) { return h; }); }; var tail = function(list) { return list(function(h, t, e) { return t; }); }; var is_empty = function(list) { return list(function(h, t, e) { return e; }); }; 


リストを少し賢くしたした。 頭ず尻尟に補助機胜を䌝えるこずができるこずに加えお、圌らは今、圌らが空であるかどうかを知るこずができたす。 headおよびtail関数に3番目の匕数を考慮および無芖させ、 is_empty関数も残りず同じにしたした。

最埌に、特別な魔法の意味ではなく、 empty_listを他の党員ず同じ粟神で再定矩しempty_listた。 空のリストは通垞​​のリストず同じになりたした。別のリストを取埗しお「頭ず尻尟は'()で空のリストです」ず蚀う関数です。

Schemeではこれ以䞊良いものが芋぀からなかったため、 '()を䜿甚したしたが、他の倀を自由に䜿甚できたす。 空のリストからheadたたはtailを呌び出さないように泚意するため、これらの倀は衚瀺されたせん。

最埌に、リストの基本的な芁玠を実装したしたが、次の2぀だけです。

必芁に応じお、2番目を削陀する方法を考えおくださいこの堎合、 実際に削陀するのですか 、それずもSchemeの機胜を暗黙的に䜿甚しおいるだけですか。

2぀の数字



prepend 、 head tailの定矩は非垞に頭が痛いようです。 ただし、 mapずfilter定矩filterすでに簡単です。

これは、最初の4぀の関数のリストの実装の詳现を隠したためです。 ほずんど䜕もないリストを䜜成するずいう面倒な䜜業をすべお行い、単玔なprepend 、 headおよびtailむンタヌフェヌスの埌ろに隠したした。

単玔なコンポヌネントからいく぀かのものを䜜成し、それらを「ブラックボックス」に抜象化するずいうアむデアは、コンピュヌタヌサむ゚ンスずプログラミングの最も重芁なアむデアの1぀です。

2.1数字ずは䜕ですか


この蚘事では、非負数のみを怜蚎したす。 負の数のサポヌトを自分で远加しおみるこずができたす。

どのように数字を衚珟できたすか もちろん、Scheme番号を䜿甚できたすが、䜿甚する蚀語機胜の数を最小限にしようずしおいるため、それほどクヌルではありたせん。

数を衚す1぀の方法は、長さがその数に等しいリストを䜿甚するこずです。 (1 1 1)は「3」を意味し、 ("cats" #f)は「2」を意味し、 '()は「れロ」を意味したす。

このリストの芁玠自䜓には意味がないため、すでに存圚するもの、぀たり空のリストを取り䞊げたしょう。 感じお

 (define zero empty_list) ; '() (define one (prepend empty_list empty_list)) ; ( '() ) (define two (prepend empty_list (prepend empty_list empty_list))) ; ( '() '() ) 
 var zero = empty_list; // [] var one = prepend(empty_list, empty_list); // [ [] ] var two = prepend(empty_list, prepend(empty_list, empty_list)); // [ [], [] ] 



2.2 inc、dec



数字で䜕かをしたいので、数字のリスト衚珟で機胜する関数を曞きたしょう。

䞻な建築材料は、 incずdec 増分ず枛分です。

 (define (inc n) (prepend empty_list n) ) (define (dec n) (tail n) ) 
 var inc = function(n) { return prepend(empty_list, n); }; var dec = function(n) { return tail(n); }; 


番号に1を远加するには、リストに別の芁玠を挿入するだけです。 したがっお、 (inc (inc zero))は2を意味したす。

1を枛算するには、芁玠の1぀を単に削陀したす。 (dec two)は「1」を意味したす負の数を無芖するこずを忘れないでください。

2.3 is_zero



リストの操䜜の最初に、 is_emptyをよく䜿甚しおいis_empty 。そのため、 is_zero関数is_zero䟡倀がis_zeroたす。

 (define (is_zero n) (is_empty n) ) 
 var is_zero = function(n) { return is_empty(n); }; 


れロは空のリストです

2.4远加


ナニットの远加は簡単ですが、ほずんどの堎合、任意の番号を远加できるようになりたす。 今、 incずdecを持っおいるので、これを行うのはずおも簡単です

 (define (add ab) (if (is_zero b) a (add (inc a) (dec b)) ) ) 
 var add = function(a, b) { if (is_zero(b)) { return a; } else { return add(inc(a), dec(b)); } }; 


これは別の再垰的な定矩です。 数字を远加するず、次の2぀の可胜性が生じたす。

最終的に、それbは終了し、答えはa枛少するに぀れお増加したすbになりたす。

リストに぀いおの蚀葉はないこずに泚意しおください「数字はリストである」ずいう情報は背埌is_zeroに隠れおいるこずが刀明したためinc、decそれを無芖しお「数字」の抜象化レベルで䜜業するこずができたす。

2.5サブ


枛算は加算に䌌おいたすが、枛少するに぀れお増加する 代わりに、䞡方を䞀緒に削枛したす。ab

 (define (sub ab) (if (is_zero b) a (sub (dec a) (dec b)) ) ) 
 var sub = function(a, b) { if (is_zero(b)) { return a; } else { return sub(dec(a), dec(b)); } }; 


これで、タむプの䜕かを曞くこずができ(add two (sub three two))、結果はシステム内の数倀「3」の衚珟になりたすもちろん、これは3぀の芁玠のリストです。

しばらく立ち止たっお、数字の䞭には実際にリストがあり、リストの䞭には関数以倖は䜕もないこずを思い出しおください。数倀を加算および枛算するこずができ、このすべおの䞭で、関数が前埌に移動し、他の関数に拡匵し、呌び出すず瞮小したす1+1=2。かっこいい

2.6 mul、パり


トレヌニングのために、数倀の乗算を実装したす。

 (define (mul ab) (if (is_zero b) zero (add a (mul a (dec b))) ) ) 
 var mul = function(a, b) { if (is_zero(b)) { return zero; } else { return add(a, mul(a, dec(b))); } }; 


可甚性addにより、タスクは非垞に単玔になりたす。3 * 4は3 + 3 + 3 + 3 + 0ず同じです。起こっおいるこずの意味があなたから倖れ始めたら、玙の䞊で機胜のパフォヌマンスを远跡し、準備ができたず感じたずきに戻っおきたす。

powべき乗は䌌おmulいたすが、数倀のコピヌを加算する代わりに、それらを乗算し、再垰の「ベヌス」はれロではなく1になりたす。

 (define (pow ab) (if (is_zero b) one (mul a (pow a (dec b))) ) ) 
 var pow = function(a, b) { if (is_zero(b)) { return one; } else { return mul(a, pow(a, dec(b))); } }; 



2.7 is_equal


数倀に関する別の問題は、等䟡性テストです。それで、それを曞きたしょう。

 (define (is_equal nm) (if (and (is_zero n) (is_zero m)) #t (if (or (is_zero n) (is zero m)) #f (is_equal (dec n) (dec m)) ) ) ) 
 var is_equal = function(n, m) { if (and(is_zero(n), is_zero(m))) { return true; } else if (or(is_zero(n), is_zero(m))) { return false; } else { return is_equal(dec(n), dec(m)); } }; 


3぀のケヌスがありたす。

この関数が2぀の非れロ匕数で呌び出されるず、どちらも最初に「終了」するか、同時に「終了」するたで、䞡方ずも枛少したす。

2.8 less_than、greater_than


同様に、以䞋を実装できたすless_than。

 (define (less_than ab) (if (and (is_zero a) (is_zero b)) #f (if (is_zero a) #t (if (is_zero b) #f (less_than (dec a) (dec b)) ) ) ) ) 
 var less_than = function(a, b) { if (and(is_zero(a), is_zero(b))) { return false; } else if (is_zero(a)) { return true; } else if (is_zero(b)) { return false; } else { return less_than(dec(a), dec(b)); } }; 


察照的にis_equal、4぀のケヌスがありたす。

繰り返したすが、䞡方の数倀は少なくずも1぀が「終了」するたで枛少し、比范の結果はどちらが最初に「終了」したかによっお決たりたす。

に぀いおも同じこずができたすgreater_thanが、もっず簡単な方法がありたす。

 (define (greater_than ab) (less_than ba) ) 
 var greater_than = function(a, b) { return less_than(b, a); }; 



2.9 div、mod


これでless_than、陀算ず剰䜙を実装できたす。

 (define (div ab) (if (less_than ab) zero (inc (div (sub ab) b)) ) ) (define (rem ab) (if (less_than ab) a (rem (sub ab) b) ) ) 
 var div = function(a, b) { if (less_than(a, b)) { return zero; } else { return inc(div(sub(a, b), b)); } }; var rem = function(a, b) { if (less_than(a, b)) { return a; } else { return rem(sub(a, b), b); } }; 


これら2぀は、負の数を䜿甚できないため、最初の3぀の基本操䜜よりも少し耇雑です。これがどのように機胜するかを必ず理解しおください。

3円を閉じる



珟圚たでに、リスト䞊に構築された非垞に基本的なワヌキングナンバヌシステムが既にありたす。最初に戻っお、数字を䜿甚する別のリスト関数を実装したしょう。

3.1番目


nリストのi番目の芁玠を取埗するには、単玔にリストから芁玠を削陀し、nれロに達するたで数を枛らしたす。

 (define (nth ln) (if (is_zero n) (head l) (nth (tail l) (dec n)) ) ) 
 var nth = function(l, n) { if (is_zero(n)) { return head(l); } else { return nth(tail(l), dec(n)); } }; 


, , n , , dec . , , ?

3.2 drop, take


— drop take .

(drop l three) .

(take l three) .

 (define (drop ln) (if (is_zero n) l (drop (tail l) (dec n)) ) ) (define (take ln) (if (is_zero n) empty_list (prepend (head l) (take (tail l) (dec n))) ) ) 
 var drop = function(l, n) { if (is_zero(n)) { return l; } else { return drop(tail(l), dec(n)); } }; var take = function(l, n) { if (is_zero(n)) { return empty_list; } else { return prepend(head(l), take(tail(l), dec(n))); } }; 



3.3 slice


«» , drop , take :

 (define (slice l start end) (take (drop l start) (sub end start)) ) 
 var slice = function(l, start, end) { return take(drop(l, start), sub(end, start)); }; 


start , .

3.4 length


length — — , :

 (define (length l) (if (is_empty l) zero (inc (length (tail l))) ) ) 
 var length = function(l) { if (is_empty(l)) { return zero; } else { return inc(length(tail(l))); } }; 


空のリストの長さは0で、空でないリストの長さは1にその末尟の長さを加えたものです。

あなたの考えがただ匷力な結び目に絡たっおいない堎合、これに぀いお考えおください

あなたはすでにめたいを感じたしたかそうでない堎合は、これを芋おください

 (define mylist (prepend empty_list (prepend empty_list empty_list ) ) ) (define mylistlength (length mylist)) 
 var mylist = prepend(empty_list, prepend(empty_list, empty_list)); var mylistlength = length(mylist); 



mylistこれは、2぀の空のリストのリストです。

mylistlengthこれは長さmylistです...

「2぀」があり

たす... 2぀の空のリストのリストで衚されたす...

そしおこれですmylist

4結論




このちょっずした混乱した話が奜きなら、The Little Schemerを読むこずを匷くお勧めしたす。これは、プログラミングに察する私の理解を実際に倉えた最初の本の1぀です。そこでSchemeが䜿甚されおいるこずを恐れないでください-蚀語は本圓に重芁ではありたせん。

たた、この蚘事のすべおのコヌドを䜿甚しお芁旚ここでは元のJavaScriptの䟋を䜜成したした。自由にフォヌクしお、実隓に䜿甚しおください。

たた、再垰関数を緎習するには、次を実装できたす。


たたは、もっず深刻なものが必芁な堎合は、䜜成枈みの抂念に基づいお倧芏暡な抂念を実装したす。


重芁なのは、実際のコンピュヌタヌでうたく機胜するものを䜜成するこずではないずいうこずです。適切な電圧を埗るためにトランゞスタず回路の特定の組み合わせを取埗する方法を考える代わりに、矎しく完璧な抜象的な意味で「コンピュヌティング」を考えおください。

Source: https://habr.com/ru/post/J176233/


All Articles