2013-04-16 30 views
15

Theo thông số F # (xem §6.5.7), đơn giản cho các vòng bị giới hạn bởi số nguyên (int aka int32 aka System.Int32) giới hạn startstop, ví dụ:Tại sao đơn giản cho các biểu thức vòng lặp được giới hạn trong phạm vi số nguyên?

for i = start to stop do 
    // do sth. 

Tôi tự hỏi tại sao giới hạn lặp lại cho loại vòng lặp này được yêu cầu là int32. Tại sao không cho phép uint32? int64? bigint?

Tôi biết rằng các biểu thức lặp tuần tự (for ... in ...) có thể lặp qua các chuỗi tùy ý; tuy nhiên yêu cầu phân bổ một iterator và gọi MoveNextCurrent và những gì không và do đó có thể được ít hơn đáng kể hiệu quả hơn một vòng lặp đơn giản có thể được (tăng truy cập, so sánh, nhảy conditonal). Để tránh điều đó, bạn đang bị mắc kẹt với việc sử dụng while và một tay incrementing quầy loop ...

Lạ lùng thay, F # không phép phi int32 giới hạn vòng lặp, nếu biểu thức for được bọc trong một biểu thức chuỗi, ví dụ

seq { for i = 0I to 10I do 
     printfn "%A" i } 

Vì vậy, tôi đoán câu hỏi là: Có lý do cụ thể để chỉ cho phép int32 cho vòng lặp không? Và tại sao hạn chế này không áp dụng cho các vòng for được bao bọc trong các biểu thức seq?

+0

Nói chung, khuôn khổ NET sử dụng 'int' như một số nguyên có mục đích chung, bao gồm cả việc sử dụng nó trong tất cả các loại tình huống lập chỉ mục số. Ví dụ: http://msdn.microsoft.com/en-us/library/system.array.indexof(v=vs.71).aspx. Ví dụ truy cập: http://msdn.microsoft.com/en-us/library/system.io.filestream.position.aspx, sử dụng từ lâu. –

+4

F # khuyến khích lập trình hàm và do đó dừng ngắn hỗ trợ bắt buộc đầy đủ (ví dụ: thiếu 'break' /' return'). Trong biểu thức tính toán 'for' được desugared vào một cuộc gọi phương thức, vốn không phải là bắt buộc như một vòng lặp, và do đó không có cùng giới hạn. Tôi có thể hiểu được bí ẩn. +1 – Daniel

+0

@Daniel +1 "Trong biểu thức tính toán cho được desugared vào một cuộc gọi phương thức". Tôi hiểu rồi; trên thực tế, mã được tạo cho 'seq {for .. to .. do ..}' và 'seq {cho .. trong .. do}' hầu như giống hệt nhau, cả hai được chuyển thành một bộ đếm 'GeneratedSequenceBase <_>'. – Frank

Trả lời

7

Tôi không chắc tại sao F # không cho phép các phạm vi int64. Nghe có vẻ như một tính năng hữu ích ... (nhưng tôi có thể hiểu rằng int là loại tiêu chuẩn cho điều này trong C# và có lẽ F # cố gắng theo mẫu này).

Đối với cách giải quyết, nó là giá trị thêm rằng bạn cũng có thể viết inline chức năng bậc cao:

let inline longFor low high f = 
    let rec loop n = 
    if n < high then f n; loop (n + 1L) 
    loop low 

... và sau đó bạn có thể bày tỏ for vòng trên int64 dãy theo một cách khá ngắn gọn:

longFor 1L 100L (fun n -> 
    <whatever>) 

tôi đã một vài thí nghiệm và dường như F # trình biên dịch có thể tối ưu hóa này khá decently (chức năng lambda được inlined và đuôi-đệ quy loop func tion được chuyển thành vòng lặp while). Tôi không nghĩ rằng đây là đảm bảo vì vậy bạn có thể cần phải kiểm tra điều này bằng tay trong mã hiệu suất cao, nhưng dường như nó hoạt động tốt cho các ví dụ đơn giản hơn.

Chỉ có một bất lợi - bạn sẽ không thể sử dụng các biến có thể thay đổi cục bộ (let mutable) vì chúng không thể được hàm lambda thu thập. Vì vậy, có thể có thêm chi phí với các tế bào ref gián tiếp (nhưng tôi không chắc chắn vấn đề lớn như thế nào).

+1

+1 Tôi cũng vừa thử nghiệm với cách trình biên dịch F # xử lý các hàm bậc cao hơn và tôi khá ngạc nhiên (và hài lòng) để thấy rằng nó thậm chí inline lambdas tại trang gọi, ít nhất là F # 3.0. Tôi bây giờ sử dụng một cách tiếp cận rất giống với gợi ý của bạn, nhưng với một vòng lặp bắt buộc trong khi thay vì đệ quy đuôi (vì vậy tôi có thể sử dụng một đồng bằng thay đổi thay vì một tế bào ref). Dường như làm việc tốt cho đến nay. – Frank

0

Cách giải quyết khác có thể:

[1L..100L] |> Danh sách.ITER (vui i -> printfn "% i" i)

2

Nếu bạn muốn giữ cho vòng lặp, có một rất đơn giản công việc xung quanh bằng cách sử dụng for...in vòng lặp với một sequence range operator:

for i in 0I .. 10I do 
    printfn "%A" i 

Các toán tử phạm vi sẽ chấp nhận bất kỳ số nguyên nào có kích thước miễn là cả hai loại đều khớp nhau. Ví dụ, sau đây sẽ không biên dịch:

for i in 0 .. 10I do 
    printfn "%A" i 
+0

Cảm ơn, nhưng tôi biết điều đó; đọc đoạn thứ hai của câu hỏi của tôi. – Frank

+0

Rất tiếc ... đã bỏ lỡ điều đó. Đã đến từ [câu hỏi khác] (http://stackoverflow.com/q/21292082/211627) ... – JDB

Các vấn đề liên quan