2009-07-13 18 views
7

Điều này liên quan đến What is call/cc?, nhưng tôi không muốn chiếm đoạt câu hỏi này cho mục đích của riêng mình và một số đối số của nó giống như sự tương tự với setjmp/longjmp né tránh tôi.Cụ thể về cuộc gọi/cc

Tôi nghĩ rằng tôi có một ý tưởng đầy đủ về những gì tiếp tục là, tôi nghĩ về nó như là một ảnh chụp nhanh của ngăn xếp cuộc gọi hiện tại. Tôi không muốn đi vào cuộc thảo luận tại sao điều này có thể thú vị hoặc những gì bạn có thể làm với sự tiếp tục. Câu hỏi của tôi cụ thể hơn, tại sao tôi phải cung cấp một đối số hàm để gọi/cc? Tại sao không gọi/cc chỉ trả lại sự tiếp tục hiện tại, vì vậy tôi có thể làm bất cứ điều gì tôi vui lòng với nó (lưu trữ nó, gọi nó, bạn tên nó)? Trong một liên kết từ câu hỏi này (http://community.schemewiki.org/?call-with-current-continuation-for-C-programmers), nó nói về "Về cơ bản nó chỉ là một cách sạch sẽ để có được sự tiếp tục cho bạn và tránh xa con đường nhảy tiếp theo trở lại điểm đã lưu.", Nhưng tôi không nhận được nó. Có vẻ phức tạp không cần thiết.

+0

Nhìn qua chủ đề này, nó hoàn toàn không rõ ràng với tôi những gì bạn đã sau, và tại sao bạn tìm thấy bài LtU chiếu sáng. Có lẽ bạn có thể chỉnh sửa câu hỏi này để giải thích những điều này tốt hơn? –

+0

Tôi nghĩ câu hỏi vẫn phản ánh chính xác điểm tôi đang đấu tranh, và đó có lẽ là thuật ngữ "thử nghiệm" của áp phích LtU đã đá vào tôi, vì nó khiến tôi nghĩ về hậu quả của việc trả lại sự tiếp tục, khi bạn gọi nó. Trích dẫn của URL schemewiki.org trong câu hỏi về cơ bản đã nắm bắt tất cả những điều này, nhưng như tôi đã nói, tôi đã không nhận được nó. Đó là ngay trong khuôn mặt của tôi, nhưng tôi đã không "nhìn thấy". Sự hiểu biết không phụ thuộc tuyến tính vào thông tin, và đôi khi nó cần một sự thay đổi. – ThomasH

+0

OK, đã hiểu! Điểm mấu chốt về con đường uốn lượn để hiểu là một cách công bằng, nhưng hơi bực mình khi cố gắng trả lời một câu hỏi, và không thể tìm ra lý do tại sao người hỏi đã từ chối nó. –

Trả lời

2

Chống lại net chung SO Tôi đang trả lời câu hỏi của riêng mình, nhưng nhiều hơn như trình chỉnh sửa so với nhà cung cấp câu trả lời.

Sau một thời gian, tôi bắt đầu một câu hỏi tương tự tại số LtU. Sau khi tất cả, đây là những kẻ suy nghĩ về thiết kế ngôn ngữ suốt cả ngày, đúng không, và một trong số answers cuối cùng đã đá vào tôi. Bây giờ mọi thứ được đề cập ở đây, ví dụ: bởi Eli hoặc trong câu hỏi ban đầu, có ý nghĩa hơn với tôi. Đó là tất cả về những gì được bao gồm trong việc tiếp tục, và nơi việc tiếp tục áp dụng đặt trong

Một trong những posters tại LTU đã viết:.

"Bạn có thể thấy chính xác cách thức gọi/cc cho phép bạn để" giữ "Với em hoặc nhận được/cc bạn cần phải làm một số loại thử nghiệm để xác định xem bạn có một cú nhảy ngược hay chỉ là cuộc gọi ban đầu. Về cơ bản, cuộc gọi/cc giữ việc sử dụng tiếp tục trong phần tiếp theo , trong khi với get/cc hoặc em, việc tiếp tục có sử dụng nó và vì vậy (thường) bạn cần phải thêm một thử nghiệm vào đầu của việc tiếp tục (tức là ngay sau get/cc/em) để tách "sử dụng các phần tiếp tục" từ phần "phần còn lại của việc tiếp tục". "

Điều đó đã mang nó về nhà cho tôi.

Xin cảm ơn các bạn!

+0

Tôi nghĩ rằng nhà cung cấp tiếp theo của Derek (loại trừ giữa) có thể được thực hiện bằng cách sử dụng get/cc. Nếu tôi tìm thấy thời gian, tôi sẽ kiểm tra điều này. –

2

Điều đó sẽ ít linh hoạt hơn. Nếu bạn muốn hành vi đó, bạn chỉ có thể làm:

(call/cc (lambda (x) x)) 

Bạn có thể có một cái nhìn tại các tập quán ví dụ về sự tiếp tục trong Gọi với Patterns Tiếp tục hiện tại 'Hội nghị lần thứ 8 trên mẫu Ngôn ngữ "Darrell Ferguson và Dwight Deugo.'. Chương trình. Tháng 9 năm 2001. " (http://library.readscheme.org/page6.html) và cố gắng viết lại chúng bằng cách sử dụng một cuộc gọi/cc-return, được định nghĩa như trên.

+0

Cảm ơn bạn đã cho thấy cách tôi có thể làm suy giảm trường hợp góc này. Nhưng tôi muốn có một lời giải thích, không phải là một giải pháp. – ThomasH

9

Nếu bạn sử dụng cấu trúc như chương trình Jay, thì bạn có thể lấy phần tiếp theo, nhưng theo cách nào đó, giá trị được lấy đã bị hỏng vì bạn đã ở trong phần tiếp theo đó. Ngược lại, call/cc có thể được sử dụng để lấy phần tiếp tục là vẫn còn đang chờ xử lý bên ngoài biểu thức hiện tại. Ví dụ: một trong những cách sử dụng đơn giản nhất của việc tiếp tục là triển khai một loại số abort:

(call/cc (lambda (abort) 
      (+ 1 2 (abort 9)))) 

Bạn không thể làm điều đó với thao tác mô tả. Nếu bạn dùng thử:

(define (get-cc) (call/cc values)) 
(let ([abort (get-cc)]) (+ 1 2 (abort 9))) 

thì bạn gặp lỗi khi áp dụng 9 làm thủ tục. Điều này xảy ra bởi vì abort nhảy trở lại let với giá trị mới của 9 - có nghĩa là bây giờ bạn đang làm một vòng thứ hai của biểu thức Ngoài cùng, ngoại trừ việc tại abort là ràng buộc để 9 ...

Hai ghi chú có liên quan bổ sung:

  1. Để có giới thiệu thực tế về tiếp tục, hãy xem PLAI.
  2. call/cc một chút phức tạp trong đó nó có chức năng - một cấu trúc dễ sử dụng khái niệm là let/cc mà bạn có thể tìm thấy trong một số triển khai như PLT Scheme. Ví dụ trên trở thành (let/cc abort (+ 1 2 (abort 9))).
+0

Vì vậy, những gì bạn nói trong điều khoản của câu hỏi của tôi, là (a) nếu tiếp tục ngay lập tức trả lại nó là "hư hỏng" bởi vì tôi là bên trong sự tiếp tục. Nhưng tôi không thể ở trong một sự tiếp tục trừ khi tôi gọi nó. Nếu sự tiếp tục là những giá trị hạng nhất, chúng không thể bị hư hỏng bằng cách truyền đi chúng, có thể chúng? Sau đó, bạn nói (b) gọi/cc sẽ lấy một "đang chờ" tiếp tục. Giá trị có thể đang chờ xử lý như thế nào?Bạn cũng nói (c) rằng sự tiếp tục là "bên ngoài" biểu thức hiện tại. Tôi không hiểu lắm. Tiếp tục chụp bao nhiêu? Tất cả mọi thứ lên đến nhưng không bao gồm các cuộc gọi để gọi/cc ?! – ThomasH

+0

Có, bạn đã ở trong sự tiếp tục. Điều về tiếp tục là chúng đại diện cho tính toán "tương lai" sau khi biểu thức cc/cuộc gọi hiện tại được thực hiện - vì vậy sau khi bạn hoàn thành (gọi/cc (lambda (k) k)), bạn sẽ tiếp tục ngay lập tức bạn vừa mới bắt. –

+0

Lưu ý, BTW, rằng quan điểm "tiếp tục đại diện cho ngăn xếp hiện tại" là hữu ích để thực hiện nó, nhưng không hiểu nó. Một cách tốt hơn để nhìn vào nó nếu bạn muốn hiểu nó là để xem nó như là bối cảnh. Ví dụ, sự tiếp tục liên kết với k trong (danh sách 1 2 (gọi/cc (lambda (k) k)) 3 4) là ngữ cảnh đang đợi câu trả lời, và sau đó tiến hành đánh giá 3 và 4, sau đó áp dụng danh sách trên 5 giá trị. Nói cách khác, bạn xem nó như sau: (danh sách 1 2 [...] 3 4). Điều này có thể khó thực hiện, bởi vì trong hầu hết các trường hợp, ngữ cảnh này là toàn cầu. Xem những tài liệu tham khảo tôi chỉ vào. –

2

Tôi khuyên bạn nên bắt đầu bằng cách tự hỏi mình: ý nghĩa của việc tiếp tục là lớp học đầu tiên là gì?

Việc tiếp tục biểu thức về cơ bản bao gồm hai phần dữ liệu: trước tiên, đóng cửa (ví dụ: môi trường) của biểu thức đó; và thứ hai, một đại diện của những gì nên được thực hiện với kết quả của biểu thức. Một ngôn ngữ với các tiếp nối hạng nhất, sau đó, là một trong đó có cấu trúc dữ liệu gói gọn các phần này và xử lý các cấu trúc dữ liệu này giống như bất kỳ cấu trúc nào khác.

Gọi/cc là một cách đặc biệt thanh lịch để nhận ra ý tưởng này: tiếp tục hiện tại được đóng gói như là một thủ tục đóng gói những gì được thực hiện với biểu thức như quy trình thực hiện khi áp dụng với biểu thức; để đại diện cho sự tiếp tục theo cách này đơn giản có nghĩa là việc đóng thủ tục này chứa môi trường tại trang mà nó được gọi.

Bạn có thể tưởng tượng việc thực hiện ý tưởng tiếp nối hạng nhất theo những cách khác. Họ sẽ không gọi/cc, và thật khó cho tôi để tưởng tượng làm thế nào một biểu diễn như vậy có thể đơn giản hơn.

Trên một lưu ý chia tay, hãy xem xét việc thực hiện các let/cc rằng Eli đã đề cập, mà tôi thích gọi bind/cc:

(define-syntax bind/cc 
    (syntax-rules() 
     ((bind/cc var . body) 
      (call/cc (lambda (var) . body))))) 

Và như một bài tập, làm thế nào bạn sẽ thực hiện cuộc gọi/cc dựa trên bind/cc?

+0

Cảm ơn bài đăng, nhưng lại một lần nữa, câu hỏi của tôi quá xa để trả lời tôi. – ThomasH