Trả lời

5

Có, yield return thực hiện một hình thức tiếp tục. Mặc dù trong nhiều trường hợp hữu ích, LINQ cung cấp các toán tử chức năng cho phép bạn kết nối với nhau một trình tạo chuỗi chậm, vì vậy trên thực tế trong C# 3, bạn không cần sử dụng yield return nhiều (ngoại trừ khi thêm các phần mở rộng kiểu Linq của riêng mình vào cắm khoảng trống trong thư viện, ví dụ Zip, Unfold).

Trong ví dụ, chúng tôi tính một số nguyên theo lực lượng vũ phu. Về cơ bản ví dụ tương tự trong C# có thể được thực hiện với sự tích hợp trong khai thác LINQ:

var factors = Enumerable.Range(2, 100) 
     .Join(Enumerable.Range(2, 100), 
       n => 1, n => 1, (i, j) => new { i, j }) 
     .First(v => v.i*v.j == 481); 

Console.WriteLine("Factors are " + factors.i + ", " + factors.j); 

Đây là điểm khởi đầu là hai cuộc gọi của tôi để Enumerable.Range, được xây dựng-in để LINQ nhưng bạn có thể thực hiện bản thân như:

IEnumerable<int> Range(int start, int stop) 
{ 
    for (int n = start; n < stop; n++) 
     yield return n; 
} 

Có hai tham số lẻ, tham số n => 1, n => 1 đến Join. Tôi đang chọn 1 làm giá trị khóa cho Join để sử dụng khi kết hợp các mục, do đó tất cả các kết hợp sẽ phù hợp và vì vậy tôi sẽ kiểm tra mọi kết hợp của các số từ các phạm vi.

Sau đó, tôi lần lượt các cặp giá trị vào một loại tuple (một loại vô danh) với:

(i, j) => new { i, j }) 

Cuối cùng, tôi chọn tuple đầu tiên như vậy mà thử nghiệm của tôi được thỏa mãn:

.First(v => v.i*v.j == 481); 

cập nhật

các mã bên cuộc gọi đến First không cần phải chỉ đơn thuần là một biểu thức kiểm tra ngắn. Nó có thể là một toàn bộ rất nhiều mã bắt buộc mà cần phải được "khởi động lại" nếu thử nghiệm thất bại:

.First(v => 
     { 
      Console.WriteLine("Aren't lambdas powerful things?"); 

      return v.i*v.j == 481; 
     ); 

Vì vậy, các phần của chương trình có tiềm năng cần phải được khởi động lại với các giá trị khác nhau đi trong lambda đó. Bất cứ khi nào lambda muốn tự khởi động lại với các giá trị khác nhau, nó chỉ trả về false - tương đương với việc gọi amb mà không có đối số.

+1

Mã đẹp - Nhưng nó có hiệu ứng hoàn toàn khác so với amb. Amb chọn giá trị của nó sao cho toàn bộ mã không bị lỗi, không chỉ tính toán sau đây. – Dario

+1

Việc "khởi động lại" phải được giới hạn trong một ngữ cảnh cụ thể, tuy nhiên nó được thực hiện; cụ thể, nó sẽ là ngớ ngẩn để khởi động lại toàn bộ chương trình bao gồm tất cả các công việc được thực hiện trước khi các biến amb được giới thiệu! Trong phiên bản của tôi, điều này được làm rõ bằng cách chuyển các biến amb vào một chuỗi, và sau đó bối cảnh có thể khởi động lại là lambda được truyền đến First - xem bản cập nhật ở trên có thể làm cho điều này rõ ràng hơn. Mã trong lambda có thể phức tạp tùy ý. –

+0

Đồng ý, mã đẹp, nhưng đây là một thực thi lực lượng vũ phu xác định. Đây không phải là một triển khai không xác định đồng thời, mà tôi tin là hai thuộc tính chính của việc thực hiện một toán tử AMB. Một lưu ý phụ, vì bài này, Rx đã được phát hành và có một toán tử Amb. –

5

Đây không phải là câu trả lời cho câu hỏi của bạn, nhưng nó có thể giúp bạn có được những gì bạn muốn.

amb được sử dụng cho tính toán không xác định. Như bạn có thể biết, Prolog là một ngôn ngữ không xác định bằng cách sử dụng khái niệm thống nhất để ràng buộc các giá trị cho các biến (về cơ bản những gì amb kết thúc lên làm).

Có triển khai thực hiện chức năng này trong C#, được gọi là YieldProlog. Như bạn đã đoán, toán tử lợi nhuận là một điều kiện tiên quyết quan trọng cho việc này.

http://yieldprolog.sourceforge.net/