2012-10-22 35 views
5

Tôi đang viết thư viện¹ trong F # cung cấp một số thao tác bitwise và tôi muốn đảm bảo nhiều chức năng nhất có thể là inline cho phép liên kết với tham số kiểu tĩnh (điều này cho phép tôi viết một hàm và sử dụng nó cho int16, int32 và thậm chí có thể là bignum với chi phí thấp). Tuyến đường này chắc chắn sẽ không hoạt động tại một số điểm. Một số chức năng được cung cấp bởi thư viện nói là hơi phức tạp.Sử dụng tham số kiểu tĩnh của F # và mã hóa hằng số

¹Lưu ý: Tôi biết về các vấn đề về việc hiển thị liên kết cho phép nội dòng qua giao diện công khai.

Tuy nhiên, tôi muốn kéo dài điều này đến mức xa nhất có thể. Ngay bây giờ, tôi đang cố gắng viết thuật toán population count trong biểu mẫu này và tôi đang gặp phải sự cố. Tôi không chắc cách mã hóa mặt nạ, ví dụ: 0x3333..., xuất hiện trong các thuật toán này. Tôi có thể nhận được xung quanh hằng số thay đổi và tương tự bằng cách sử dụng một số thủ thuật thêm chút.

Có mẹo nào tôi có thể sử dụng hay không, cho dù thông qua kiểu suy luận kiểu và tham số kiểu F # hay thông qua bit-twiddling, để viết thuật toán theo cách tôi muốn? Có cách nào tôi có thể mã hóa các loại hằng số trong các chức năng chung tĩnh?

Một câu hỏi mơ hồ hơn: có một số điều cụ thể mà tôi có thể dựa vào để sử dụng các tham số kiểu tĩnh cho đầy đủ nhất, đặc biệt là trong ngữ cảnh của số học không? Ví dụ: tôi sử dụng rất nhiều GenericOneGenericZero. Có nhiều thứ như thế này, mà tôi có thể đã bỏ lỡ?

+2

Về nguồn lực, một lừa là hữu ích để xác định chữ số chung để bạn có thể viết ví dụ '42g '(xem http://stackoverflow.com/questions/4732672/how-to-write-a-function-for-generic-numbers). Tôi cũng đã viết một bài báo với một số thông tin nhiều hơn, nhưng tôi nghĩ rằng bạn có thể sẽ không tìm thấy nhiều mới ở đó (xem http://tomasp.net/blog/fsharp-generic-numeric.aspx). –

+0

Sử dụng chữ số chung chung, bạn có thể viết tức là 'let inline shift a = (a &&& 8G) <<< 2', nhưng tôi cho rằng đó không phải là câu trả lời cho câu hỏi của bạn (vì bạn có thể làm điều đó với 'GenericOne') . Vì vậy, bạn có bất kỳ ví dụ cụ thể phức tạp hơn, nơi cách tiếp cận trực tiếp không hoạt động cho bạn? –

+3

'0x33 ...' là ''signedtype'.MaxValue/5 * 2 + 1', điều đó có giúp ích gì không? – harold

Trả lời

5

Trước tiên, bạn có thể sử dụng numeric literals để tránh việc sử dụng xấu xí của GenericOneGenericZero. Dưới đây là một ví dụ ngắn gọn:

module NumericLiteralG = begin 
    let inline FromZero() = LanguagePrimitives.GenericZero 
    let inline FromOne() = LanguagePrimitives.GenericOne 
    let inline FromInt32 (n:int) = 
     let one : ^a = FromOne() 
     let zero : ^a = FromZero() 
     let n_incr = if n > 0 then 1 else -1 
     let g_incr = if n > 0 then one else (zero - one) 
     let rec loop i g = 
      if i = n then g 
      else loop (i + n_incr) (g + g_incr) 
     loop 0 zero 
end 

// Usage 
let inline ten() = 10G 
ten() + 1 
ten() + 2L 

Thứ hai, F # dường như không ủng hộ generic hexa literals số. Một mẹo là sử dụng các dấu gạch chéo kép để bạn có tên chỉ dẫn:

let inline shift x = 
    let ``0x33333333G`` = 858993459G 
    ((x >>> 2) &&& ``0x33333333G``) + (x &&& ``0x33333333G``) 

// Usage 
shift 20 
shift 20L 
shift 20uy 

Có một số câu hỏi hay về SO về chữ số. Tôi đưa ra một số tài liệu tham khảo trong trường hợp bạn đi là con đường:

+0

Điều đó thật thú vị. Tôi sẽ đọc thành các chữ số như thế này, và cũng xem xét các câu hỏi SO mà bạn đã đề cập. Tôi muốn chỉ ra rằng mặc dù, nói chung, không có vấn đề với hex chữ số trong F #.Có thể có vấn đề với bạn sử dụng 'G' literals ... – GregRos

+0

Có, bởi vì' 0x33333333I' không hoạt động (có ý nghĩa), tôi không mong đợi '0x33333333G' hoạt động. – pad

+0

Cảm ơn :) Câu trả lời này đã giúp tôi rất nhiều. Ngoài ra, tôi muốn chỉ ra rằng thuật toán cho 'FromInt' không hiệu quả lắm. [Ở đây] (https://snipt.net/GregRos/-1040/) là một triển khai tốt hơn, mặc dù nó chỉ hoạt động cho các số nguyên. – GregRos

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