Lấy cảm hứng từ câu trả lời bằng NumericLiterals kvb, tôi đã được thúc đẩy để phát triển một phương pháp mà sẽ cho phép chúng tôi để ép buộc các chữ ký kiểu "lành mạnh" mà không cần phải thêm các chú thích kiểu mở rộng.
Đầu tiên chúng ta định nghĩa một số chức năng helper và loại wrapper cho nguyên thủy ngôn ngữ:
let inline zero_of (target:'a) : 'a = LanguagePrimitives.GenericZero<'a>
let inline one_of (target:'a) : 'a = LanguagePrimitives.GenericOne<'a>
let inline two_of (target:'a) : 'a = one_of(target) + one_of(target)
let inline three_of (target:'a) : 'a = two_of(target) + one_of(target)
let inline negone_of (target:'a) : 'a = zero_of(target) - one_of(target)
let inline any_of (target:'a) (x:int) : 'a =
let one:'a = one_of target
let zero:'a = zero_of target
let xu = if x > 0 then 1 else -1
let gu:'a = if x > 0 then one else zero-one
let rec get i g =
if i = x then g
else get (i+xu) (g+gu)
get 0 zero
type G<'a> = {
negone:'a
zero:'a
one:'a
two:'a
three:'a
any: int -> 'a
}
let inline G_of (target:'a) : (G<'a>) = {
zero = zero_of target
one = one_of target
two = two_of target
three = three_of target
negone = negone_of target
any = any_of target
}
Sau đó, chúng ta có:
let inline factorizeG n =
let g = G_of n
let rec factorize n j flist =
if n = g.one then flist
elif n % j = g.zero then factorize (n/j) j (j::flist)
else factorize n (j + g.one) (flist)
factorize n g.two []
[Sửa: do một lỗi rõ ràng với F # 2.0 /. NET 2.0, factorizen, factorizeL và factorizeI bên dưới chạy chậm hơn đáng kể so với factorizeG khi được biên dịch trong chế độ Release-mode nhưng nếu không chạy nhanh hơn một chút như mong đợi - xem F# performance question: what is the compiler doing?]
Hoặc chúng ta có thể mang nó một vài bước xa hơn (lấy cảm hứng từ Expert F #, p.110):
let inline factorize (g:G<'a>) n = //'
let rec factorize n j flist =
if n = g.one then flist
elif n % j = g.zero then factorize (n/j) j (j::flist)
else factorize n (j + g.one) (flist)
factorize n g.two []
//identical to our earlier factorizeG
let inline factorizeG n = factorize (G_of n) n
let gn = G_of 1 //int32
let gL = G_of 1L //int64
let gI = G_of 1I //bigint
//allow us to limit to only integral numeric types
//and to reap performance gain by using pre-computed instances of G
let factorizen = factorize gn
let factorizeL = factorize gL
let factorizeI = factorize gI
Ngoài ra, đây là một phiên bản mở rộng của NumericLiteralG kvb của cho phép chúng ta sử dụng "2G", " -8G ", v.v.Mặc dù tôi không thể tìm ra cách để thực hiện một chiến lược ghi nhớ (mặc dù điều đó có thể thực hiện được đối với G.any).
module NumericLiteralG =
let inline FromZero() = LanguagePrimitives.GenericZero
let inline FromOne() = LanguagePrimitives.GenericOne
let inline FromInt32(n:int):'a =
let one:'a = FromOne()
let zero:'a = FromZero()
let nu = if n > 0 then 1 else -1
let gu:'a = if n > 0 then one else zero-one
let rec get i g =
if i = n then g
else get (i+nu) (g+gu)
get 0 zero
Nguồn
2010-05-15 23:01:20
Thật tuyệt vời. –
Bạn nói đúng - công trình này - khá bất ngờ đối với tôi :-). Tôi không chắc chắn những gì đang xảy ra ở đây, bởi vì 'factorize' được biên dịch như một hàm tổng quát. Nó sử dụng triển khai động 'GetZero' (có thể tương tự như sử dụng' NumericAssociations'), nhưng tôi không chắc cách thức hoạt động (không đăng ký rõ ràng các hoạt động cho kiểu của riêng bạn). Nếu bạn hiểu cách làm việc này, tôi sẽ khá quan tâm đến các chi tiết :-). –
Chỉ cần nhận thấy tối ưu hóa tốt đẹp mà bạn đã thêm vào trong trường hợp elif cho chính thuật toán. –